// SPDX-License-Identifier: GPL-2.0
/*  Himax Android Driver Sample Code for common functions
 *
 *  Copyright (C) 2021 Himax Corporation.
 *
 *  This software is licensed under the terms of the GNU General Public
 *  License version 2,  as published by the Free Software Foundation,  and
 *  may be copied,  distributed,  and modified under those terms.
 *
 *  This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 */

/*#include "himax_common.h"*/
/*#include "himax_ic_core.h"*/
#include "himax_self_test.h"
#include "himax_modular.h"
#if defined(__HIMAX_MOD__)
int (*hx_msm_drm_register_client)(struct notifier_block *nb);
int (*hx_msm_drm_unregister_client)(struct notifier_block *nb);
#endif

#if (HX_SMART_WAKEUP == 0x01)
#define GEST_SUP_NUM 2
/* Setting cust key define (DF = double finger) */
/* {Double Tap, Tap}
 */
uint8_t gest_event[GEST_SUP_NUM] = { 0x80, 0x90 };

/*gest_event mapping to gest_key_def*/
uint16_t gest_key_def[GEST_SUP_NUM] = { HX_KEY_DOUBLE_CLICK,
					HX_KEY_SINGLE_CLICK };

uint8_t *wake_event_buffer;
#endif

#define SUPPORT_FINGER_DATA_CHECKSUM 0x0F
#define TS_WAKE_LOCK_TIMEOUT (5000)
#define FRAME_COUNT 5

uint32_t g_hx_chip_inited;

#if defined(__EMBEDDED_FW__)
struct firmware g_embedded_fw = {
	.data = _binary___Himax_firmware_bin_start,
};
#endif

#if (HX_BOOT_UPGRADE == 0x01)
bool g_boot_upgrade_flag;
const struct firmware *hxfw;
int g_i_FW_VER;
int g_i_CFG_VER;
int g_i_CID_MAJ; /*GUEST ID*/
int g_i_CID_MIN; /*VER for GUEST*/
#endif

struct himax_ts_data *private_ts;
EXPORT_SYMBOL(private_ts);

struct himax_ic_data *ic_data;
EXPORT_SYMBOL(ic_data);

struct himax_report_data *hx_touch_data;
EXPORT_SYMBOL(hx_touch_data);

struct himax_core_fp g_core_fp;
EXPORT_SYMBOL(g_core_fp);

struct himax_debug *debug_data;
EXPORT_SYMBOL(debug_data);

struct proc_dir_entry *himax_touch_proc_dir;
EXPORT_SYMBOL(himax_touch_proc_dir);

int g_mmi_refcnt;
EXPORT_SYMBOL(g_mmi_refcnt);

#define HIMAX_PROC_TOUCH_FOLDER "android_touch"
/*ts_work about start*/
struct himax_target_report_data *g_target_report_data;
EXPORT_SYMBOL(g_target_report_data);

struct himax_target_report_data *fixed_point_label;
EXPORT_SYMBOL(fixed_point_label);

/*ts_work about end*/
static int HX_TOUCH_INFO_POINT_CNT;

#if (HX_EXCP_RECOVERY == 0x01)
u8 HX_EXCP_RESET_ACTIVATE;
EXPORT_SYMBOL(HX_EXCP_RESET_ACTIVATE);

int g_zero_event_count;

#endif

static bool chip_test_r_flag;

static uint8_t AA_press;
static uint8_t EN_NoiseFilter;
static uint8_t Last_EN_NoiseFilter;
static int p_point_num = 0xFFFF;
static int probe_fail_flag;

#if (HX_GESTURE_TRACK == 0x01)
static int gest_pt_cnt;
static int gest_pt_x[GEST_PT_MAX_NUM];
static int gest_pt_y[GEST_PT_MAX_NUM];
static int gest_start_x, gest_start_y, gest_end_x, gest_end_y;
static int gest_width, gest_height, gest_mid_x, gest_mid_y;
static int hx_gesture_coor[16];
#endif

int g_ts_dbg;
EXPORT_SYMBOL(g_ts_dbg);

#define HIMAX_PROC_SELF_TEST_FILE "self_test"
struct proc_dir_entry *himax_proc_self_test_file;

#define HIMAX_PROC_WP_BP_LOCK_FILE "WPBPlock_node"
struct proc_dir_entry *himax_proc_WPBPlock_node_file;

#define HIMAX_PROC_FAIL_DET_FILE "Faildet_E5_bank0_bank1_bank3"
struct proc_dir_entry *himax_proc_fail_det_file;

uint8_t HX_PROC_SEND_FLAG;
EXPORT_SYMBOL(HX_PROC_SEND_FLAG);

#define HIMAX_PROC_GTS_FILE "Ghost_touch_solution"
struct proc_dir_entry *himax_proc_GTS_file;
#if (HX_SMART_WAKEUP == 0x01)
#define HIMAX_PROC_SMWP_FILE "SMWP"
struct proc_dir_entry *himax_proc_SMWP_file;
#define HIMAX_PROC_GESTURE_FILE "GESTURE"
struct proc_dir_entry *himax_proc_GESTURE_file;
uint8_t HX_SMWP_EN;
#endif

#if (HX_TP_INSPECT_MODE == 0x01)
#define HIMAX_PROC_INSPECT_MODE_FILE "Inspect_mode"
struct proc_dir_entry *himax_proc_INSPECT_MODE_file;
uint8_t inspect_mode_flag;
#endif

struct timespec64 time_diff(struct timespec64 start, struct timespec64 end)
{
	struct timespec64 delta;

	if ((end.tv_nsec - start.tv_nsec) < 0) {
		delta.tv_sec = end.tv_sec - start.tv_sec - 1;
		delta.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
	} else {
		delta.tv_sec = end.tv_sec - start.tv_sec;
		delta.tv_nsec = end.tv_nsec - start.tv_nsec;
	}
	return delta;
}

static ssize_t himax_self_test(struct seq_file *s, void *v)
{
	int val = 0x00;
	size_t ret = 0;

	I("%s: enter, %d\n", __func__, __LINE__);

	if (private_ts->suspended == 1) {
		E("%s: please do self test in normal active mode\n", __func__);
		return HX_INIT_FAIL;
	}
	himax_int_enable(0); /* disable irq */

	private_ts->in_self_test = 1;

	val = himax_chip_self_test(s, v);

	private_ts->in_self_test = 0;

#if (HX_EXCP_RECOVERY == 0x01)
	HX_EXCP_RESET_ACTIVATE = 1;
#endif
	himax_int_enable(1);

	return ret;
}

static void *himax_self_test_seq_start(struct seq_file *s, loff_t *pos)
{
	if (*pos >= 1)
		return NULL;

	return (void *)((unsigned long)*pos + 1);
}

static void *himax_self_test_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
	return NULL;
}

static void himax_self_test_seq_stop(struct seq_file *s, void *v)
{
}

static int himax_self_test_seq_read(struct seq_file *s, void *v)
{
	size_t ret = 0;

	if (chip_test_r_flag) {
#if defined(CONFIG_TOUCHSCREEN_HIMAX_SELF_TEST)
		if (g_rslt_data)
			seq_printf(s, "%s", g_rslt_data);
		else

			seq_puts(s, "No chip test data.\n");
	} else {
		himax_self_test(s, v);
#endif
	}

	return ret;
}

static const struct seq_operations himax_self_test_seq_ops = {
	.start = himax_self_test_seq_start,
	.next = himax_self_test_seq_next,
	.stop = himax_self_test_seq_stop,
	.show = himax_self_test_seq_read,
};

static int himax_self_test_proc_open(struct inode *inode, struct file *file)
{
	return seq_open(file, &himax_self_test_seq_ops);
};

static ssize_t himax_self_test_write(struct file *filp, const char __user *buff,
				     size_t len, loff_t *data)
{
	char buf[80];

	if (len >= 80) {
		I("%s: no command exceeds 80 chars.\n", __func__);
		return -EFAULT;
	}

	if (copy_from_user(buf, buff, len))
		return -EFAULT;

	if (buf[0] == 'r') {
		chip_test_r_flag = true;
		I("%s: Start to read chip test data.\n", __func__);
	} else {
		chip_test_r_flag = false;
		I("%s: Back to do self test.\n", __func__);
	}

	return len;
}

static void *himax_WPBPlock_node_seq_start(struct seq_file *s, loff_t *pos)
{
	if (*pos >= 1)
		return NULL;

	return (void *)((unsigned long)*pos + 1);
}

static void *himax_WPBPlock_node_seq_next(struct seq_file *s, void *v,
					  loff_t *pos)
{
	return NULL;
}

static void himax_WPBPlock_node_seq_stop(struct seq_file *s, void *v)
{
}

static int himax_WPBPlock_node_seq_read(struct seq_file *s, void *v)
{
	size_t ret = 0;
	uint8_t status;

	status = himax_mcu_WP_BP_status();

	if (status == 1)
		seq_printf(s, "WP BP value & lock status is lock \n");
	else
		seq_printf(s, "WP BP lock status is unlock \n");

	return ret;
}

static const struct seq_operations himax_WPBPlock_node_seq_ops = {
	.start = himax_WPBPlock_node_seq_start,
	.next = himax_WPBPlock_node_seq_next,
	.stop = himax_WPBPlock_node_seq_stop,
	.show = himax_WPBPlock_node_seq_read,
};

static int himax_WPBPlock_node_proc_open(struct inode *inode, struct file *file)
{
	return seq_open(file, &himax_WPBPlock_node_seq_ops);
};

static ssize_t himax_WPBPlock_node_write(struct file *filp,
					 const char __user *buff, size_t len,
					 loff_t *data)
{
	char buf[80];
	int result = 0;

	if (len >= 80) {
		I("%s: no command exceeds 80 chars.\n", __func__);
		return -EFAULT;
	}

	if (copy_from_user(buf, buff, len))
		return -EFAULT;

	if ((buf[0] == 'd') || (buf[0] == 'D')) {
		I("%s: Start to disable BP lock.\n", __func__);
		result = himax_disable_flash_protected_mode();

	} else if ((buf[0] == 'e') || (buf[0] == 'E')) {
		I("%s: Start to enable BP lock.\n", __func__);
		result = himax_enable_flash_protected_mode();
	} else {
		I("%s: Input cmd is incorrect!\n", __func__);
	}

	return len;
}

static void *himax_fail_det_seq_start(struct seq_file *s, loff_t *pos)
{
	if (*pos >= 1)
		return NULL;

	return (void *)((unsigned long)*pos + 1);
}

static void *himax_fail_det_seq_next(struct seq_file *s, void *v, loff_t *pos)
{
	return NULL;
}

static void himax_fail_det_seq_stop(struct seq_file *s, void *v)
{
}

static int himax_fail_det_seq_read(struct seq_file *s, void *v)
{
	size_t ret = 0;
	uint8_t data[8] = { 0 };
	uint8_t tmp_data[DATA_LEN_4] = { 0 };
	char *vertical_title[8] = { "0st_Parameter", "1st_Parameter",
				    "2st_Parameter", "3st_Parameter",
				    "4st_Parameter", "5st_Parameter",
				    "6st_Parameter", "7st_Parameter" };
	int i = 0;

	g_core_fp.fp_dd_clk_set(true);
	g_core_fp.fp_dd_reg_en(true);

	himax_mcu_dd_reg_read(0xE5, 0, 8, data, 0);
	seq_printf(
		s,
		"E5_Bank0:	para[1]=0x%2.2X,	para[2]=0x%2.2X,	para[3]=0x%2.2X,\
	para[4]=0x%2.2X,	para[5]=0x%2.2X,	para[6]=0x%2.2X,	para[7]=0x%2.2X\n",
		data[1], data[2], data[3], data[4], data[5], data[6], data[7]);

	seq_puts(
		s,
		"---E5h-Bank0--\t|\tD7\t|\tD6\t|\tD5\t|\tD4\t|\tD3\t|\tD2\t|\tD1\t|\tD0\t|\n");

	for (i = 1; i < 8; i++) {
		seq_printf(
			s,
			"%s\t|\t%d\t|\t%d\t|\t%d\t|\t%d\t|\t%d\t|\t%d\t|\t%d\t|\t%d\t|\n",
			vertical_title[i], (data[i] >> 7) & 0x01,
			(data[i] >> 6) & 0x01, (data[i] >> 5) & 0x01,
			(data[i] >> 4) & 0x01, (data[i] >> 3) & 0x01,
			(data[i] >> 2) & 0x01, (data[i] >> 1) & 0x01,
			data[i] & 0x01);
	}

	himax_mcu_dd_reg_read(0xE5, 0, 8, data, 1);
	seq_printf(
		s,
		"E5_Bank1:	para[1]=0x%2.2X,	para[2]=0x%2.2X,	para[3]=0x%2.2X,\
	para[4]=0x%2.2X,	para[5]=0x%2.2X,	para[6]=0x%2.2X,	para[7]=0x%2.2X\n",
		data[1], data[2], data[3], data[4], data[5], data[6], data[7]);

	seq_puts(
		s,
		"---E5h-Bank1--\t|\tD7\t|\tD6\t|\tD5\t|\tD4\t|\tD3\t|\tD2\t|\tD1\t|\tD0\t|\n");

	for (i = 1; i < 7; i++) {
		seq_printf(
			s,
			"%s\t|\t%d\t|\t%d\t|\t%d\t|\t%d\t|\t%d\t|\t%d\t|\t%d\t|\t%d\t|\n",
			vertical_title[i], (data[i] >> 7) & 0x01,
			(data[i] >> 6) & 0x01, (data[i] >> 5) & 0x01,
			(data[i] >> 4) & 0x01, (data[i] >> 3) & 0x01,
			(data[i] >> 2) & 0x01, (data[i] >> 1) & 0x01,
			data[i] & 0x01);
	}

	himax_mcu_dd_reg_read(0xE5, 0, 8, data, 3);
	seq_printf(
		s,
		"E5_Bank3:	para[5]=0x%2.2X,	para[6]=0x%2.2X,	para[7]=0x%2.2X\n",
		data[5], data[6], data[7]);

	seq_puts(
		s,
		"---E5h-Bank3--\t|\tD7\t|\tD6\t|\tD5\t|\tD4\t|\tD3\t|\tD2\t|\tD1\t|\tD0\t|\n");

	for (i = 5; i < 8; i++) {
		seq_printf(
			s,
			"%s\t|\t%d\t|\t%d\t|\t%d\t|\t%d\t|\t%d\t|\t%d\t|\t%d\t|\t%d\t|\n",
			vertical_title[i], (data[i] >> 7) & 0x01,
			(data[i] >> 6) & 0x01, (data[i] >> 5) & 0x01,
			(data[i] >> 4) & 0x01, (data[i] >> 3) & 0x01,
			(data[i] >> 2) & 0x01, (data[i] >> 1) & 0x01,
			data[i] & 0x01);
	}

	g_core_fp.fp_dd_clk_set(false);

	I("%s: now read GPIO[1] Fail information.\n", __func__);

	himax_mcu_register_read(addr_fail_det_GPIO1_msg, DATA_LEN_4, tmp_data);
	I("%s: 100074C0 value is: tmp_data[0] = 0x%2.2x, tmp_data[1] = 0x%2.2x\n",
	  __func__, tmp_data[0], tmp_data[1]);
	I("%s: 100074C0 value is: tmp_data[2] = 0x%2.2x, tmp_data[3] = 0x%2.2x\n",
	  __func__, tmp_data[2], tmp_data[3]);
	seq_printf(
		s,
		"100074C0 value is tmp_data[0] = 0x%2.2x, tmp_data[1] = 0x%2.2x, tmp_data[2] = 0x%2.2x, tmp_data[3] = 0x%2.2x.\n",
		tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]);

	return ret;
}

static const struct seq_operations himax_fail_det_seq_ops = {
	.start = himax_fail_det_seq_start,
	.next = himax_fail_det_seq_next,
	.stop = himax_fail_det_seq_stop,
	.show = himax_fail_det_seq_read,
};

static int himax_fail_det_proc_open(struct inode *inode, struct file *file)
{
	return seq_open(file, &himax_fail_det_seq_ops);
};

static ssize_t himax_fail_det_write(struct file *filp, const char __user *buff,
				    size_t len, loff_t *data)
{
	/*not implement write function*/
	char buf[80] = "\0";
	uint8_t tmp_data[4] = { 0 };

	if (len >= 80) {
		I("%s: no command exceeds 80 chars.\n", __func__);
		return -EFAULT;
	}

	if (copy_from_user(buf, buff, len))
		return -EFAULT;

	if (buf[0] == 'c' || buf[0] == 'C') {
		I("%s: now clear E5 Bank3 value.\n", __func__);
		g_core_fp.fp_dd_clk_set(true);
		g_core_fp.fp_dd_reg_en(true);

		himax_mcu_dd_reg_read(0xE5, 0, 4, tmp_data, 0);
		I("0xE5 Bank0 pa1: data[0] = 0x%2.2x, data[1] = 0x%2.2x, data[2] = 0x%2.2x, data[3] = 0x%2.2x.\n",
		  tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]);

		tmp_data[0] = 0x03;
		himax_mcu_dd_reg_write(0xE5, 1, 1, tmp_data, 0);

		tmp_data[0] = 0x00;
		himax_mcu_dd_reg_read(0xE5, 0, 4, tmp_data, 0);
		I("0xE5 Bank0 pa1: data[0] = 0x%2.2x, data[1] = 0x%2.2x, data[2] = 0x%2.2x, data[3] = 0x%2.2x.\n",
		  tmp_data[0], tmp_data[1], tmp_data[2], tmp_data[3]);

		g_core_fp.fp_dd_clk_set(false);
	}

	return len;
}

static const struct  proc_ops himax_proc_self_test_ops = {
	.proc_open = himax_self_test_proc_open,
	.proc_read = seq_read,
	.proc_write = himax_self_test_write,
	.proc_release = seq_release,
};

static const struct proc_ops himax_proc_WPBPlock_node_ops = {
	.proc_open = himax_WPBPlock_node_proc_open,
	.proc_read = seq_read,
	.proc_write = himax_WPBPlock_node_write,
	.proc_release = seq_release,
};

static const struct proc_ops himax_proc_fail_det_ops = {
	.proc_open = himax_fail_det_proc_open,
	.proc_read = seq_read,
	.proc_write = himax_fail_det_write,
	.proc_release = seq_release,
};

#if (HX_TP_INSPECT_MODE == 0x01)
static void himax_set_BS_DUT_frame(uint8_t frame)
{
	uint8_t tmp_data[DATA_LEN_4] = { 0 };

	/*skip frame 0x100070F4*/
	himax_mcu_register_read(addr_skip_frame, DATA_LEN_4, tmp_data);

	tmp_data[0] = frame;

	himax_mcu_register_write(addr_skip_frame, 4, tmp_data);
}

static int himax_chip_inspect_mode(struct seq_file *s, void *v)
{
	uint32_t tmp_addr_32 = 0x10007454;
	uint32_t addr_stack_depth = 0x8006000C;
	uint8_t tmp_data[DATA_LEN_4] = { 0 };
	char buf[64] = { 0 };
	int cnt = 0;
	bool is_done = false;
	int16_t Low_bound;
	struct timespec64 timeStart, timeEnd, timeDelta;

	switch (inspect_mode_flag) {
	case 0x01: /*Start to do Short_test*/
		tmp_data[3] = 0x5A;
		tmp_data[2] = 0x00;
		tmp_data[1] = 0x01;
		tmp_data[0] = 0xA5;
		seq_puts(s, "Item : Short_test.\n");
		break;
	case 0x02: /*Start to do Open_test*/
		tmp_data[3] = 0x5A;
		tmp_data[2] = 0x00;
		tmp_data[1] = 0x02;
		tmp_data[0] = 0xA4;
		seq_puts(s, "Item : Open_test.\n");
		break;
	case 0x08: /*Start to do Noise_test*/
		tmp_data[3] = 0x5A;
		tmp_data[2] = 0x00;
		tmp_data[1] = 0x08;
		tmp_data[0] = 0x9E;
		seq_puts(s, "Item : Noise_test.\n");
		break;
	case 0x0B: /*Start to do All_test*/
		tmp_data[3] = 0x5A;
		tmp_data[2] = 0x00;
		tmp_data[1] = 0x0B;
		tmp_data[0] = 0x9B;
		seq_puts(s, "Item : All_test.\n");
		break;
	default:
		return false;
		seq_puts(s, "Input cmd is incorrect.\n");
	}
	 ktime_get_real_ts64(&timeStart);

	himax_mcu_reload_disable(1);
	himax_set_BS_DUT_frame(1);

	usleep_range(20000, 21000);

	himax_mcu_register_write(tmp_addr_32, DATA_LEN_4, tmp_data);
	himax_mcu_register_read(tmp_addr_32, DATA_LEN_4, tmp_data);

	I("Now register =0x%02X, 0x%02X, 0x%02X, 0x%02X\n", tmp_data[3],
	  tmp_data[2], tmp_data[1], tmp_data[0]);

	cnt = 0;
	while (cnt++ < 100) {
		himax_mcu_register_read(tmp_addr_32, DATA_LEN_4, tmp_data);
		usleep_range(20000, 21000);
		I("%s : Current Status = 0x%02X\n", __func__, tmp_data[3]);
		if (tmp_data[3] == 0xA5)
			break;
	}
	I("%s : Waiting for Inspect mode , loop conut = %d\n", __func__, cnt);
	if (tmp_data[3] != 0xA5) {
		I("%s : Fail Status = 0x%02X, 0x%02X, 0x%02X, 0x%02X\n", __func__,
		tmp_data[3], tmp_data[2], tmp_data[1], tmp_data[0]);
		seq_puts(s, "FW not support Inspect mode.\n");
		return false;
	}
	cnt = 0;
	while (cnt++ < 600) {
		usleep_range(20000, 21000);
		himax_mcu_register_read(addr_stack_depth, DATA_LEN_4, tmp_data);
		if (tmp_data[0] == 0x28) {
			is_done = true;
			break;
		}
	}
	I("%s : stack depth 0x%02X , loop conut %d\n", __func__, tmp_data[0],
	  cnt);
	himax_mcu_reload_disable(0);

	himax_mcu_read_event_stack(buf, 40);

	I("%s : %s = 0x%02X, 0x%02X, 0x%02X, 0x%02X , loop conut %d\n",
	  __func__, "Stack result", buf[0], buf[1], buf[2], buf[3], cnt);

	 ktime_get_real_ts64(&timeEnd);
	timeDelta = time_diff(timeStart, timeEnd);
	seq_printf(s, "\tDuration :  %ld.%ld s\n", timeDelta.tv_sec,
		   timeDelta.tv_nsec);

	if (is_done) {
		if (buf[3] == 0x01) {
			switch (inspect_mode_flag) {
			case 0x01: /*Start to do Short_test*/
				seq_printf(s, "\tShort Test : %s\n",
					   ((buf[7] & 0x01) == 0x01) ? "Fail" :
									     "Pass");
				Low_bound = ((buf[14] << 8) + buf[15]);
				Low_bound = (Low_bound > 0xFF00) ?
							  (0xFF00 - Low_bound) :
							  Low_bound;
				seq_printf(s, "\t%s = %5d / %5d\n",
					   "Short Max. / Min.",
					   ((buf[12] << 8) + buf[13]),
					   Low_bound);
				break;
			case 0x02: /*Start to do Open_test*/
				seq_printf(s, "\tOpen  Test : %s\n",
					   ((buf[7] & 0x02) == 0x02) ? "Fail" :
									     "Pass");
				Low_bound = ((buf[18] << 8) + buf[19]);
				Low_bound = (Low_bound > 0xFF00) ?
							  (0xFF00 - Low_bound) :
							  Low_bound;
				seq_printf(s, "\t%s = %5d / %5d\n",
					   "Open  Max. / Min.",
					   ((buf[16] << 8) + buf[17]),
					   Low_bound);
				break;
			case 0x08: /*Start to do Noise_test*/
				seq_printf(s, "\tNoise Test : %s\n",
					   ((buf[7] & 0x08) == 0x08) ? "Fail" :
									     "Pass");
				Low_bound = ((buf[26] << 8) + buf[27]);
				Low_bound = (Low_bound > 0xFF00) ?
							  (0xFF00 - Low_bound) :
							  Low_bound;
				seq_printf(s, "\t%s = %5d / %5d\n",
					   "Noise Max. / Min.",
					   ((buf[24] << 8) + buf[25]),
					   Low_bound);
				// seq_printf(s, "%s = %5d / %5d\n", "Noise Max. / Min.", ((buf[24] << 8) + buf[25]), ((buf[26] << 8) + buf[27]));
				break;
			case 0x0B: /*Start to do All_test*/
				seq_printf(s, "\tShort Test : %s\n",
					   ((buf[7] & 0x01) == 0x01) ? "Fail" :
									     "Pass");
				seq_printf(s, "\tOpen  Test : %s\n",
					   ((buf[7] & 0x02) == 0x02) ? "Fail" :
									     "Pass");
				seq_printf(s, "\tNoise Test : %s\n",
					   ((buf[7] & 0x08) == 0x08) ? "Fail" :
									     "Pass");
				Low_bound = ((buf[14] << 8) + buf[15]);
				Low_bound = (Low_bound > 0xFF00) ?
							  (0xFF00 - Low_bound) :
							  Low_bound;
				seq_printf(s, "\t%s = %5d / %5d\n",
					   "Short Max. / Min.",
					   ((buf[12] << 8) + buf[13]),
					   Low_bound);
				Low_bound = ((buf[18] << 8) + buf[19]);
				Low_bound = (Low_bound > 0xFF00) ?
							  (0xFF00 - Low_bound) :
							  Low_bound;
				seq_printf(s, "\t%s = %5d / %5d\n",
					   "Open  Max. / Min.",
					   ((buf[16] << 8) + buf[17]),
					   Low_bound);
				Low_bound = ((buf[26] << 8) + buf[27]);
				Low_bound = (Low_bound > 0xFF00) ?
							  (0xFF00 - Low_bound) :
							  Low_bound;
				seq_printf(s, "\t%s = %5d / %5d\n",
					   "Noise Max. / Min.",
					   ((buf[24] << 8) + buf[25]),
					   Low_bound);
				break;
			default:
				seq_puts(s, "Input cmd is incorrect.\n");
			}
		} else if (buf[3] == 0x10)
			seq_printf(s, "%s\n", "Self Test command error.");
		else if (buf[3] == 0x20)
			seq_printf(s, "%s\n", "Self Test command CRC error.");

		I("%s = 0x%02X, 0x%02X, 0x%02X, 0x%02X\n", "Test Result",
		  buf[4], buf[5], buf[6], buf[7]);
		I("%s = 0x%02X, 0x%02X, 0x%02X, 0x%02X\n", "Result Information",
		  buf[8], buf[9], buf[10], buf[11]);

	} else
		seq_puts(
			s,
			"[ERROR] Inspect Mode has not Completed! Please check if FW support it or not!\n");

	return true;
}

static ssize_t himax_inspect_mode(struct seq_file *s, void *v)
{
	int val = 0x00;
	size_t ret = 0;

	I("%s: enter, %d\n", __func__, __LINE__);

	if (private_ts->suspended == 1) {
		E("%s: please do self test in normal active mode\n", __func__);
		return HX_INIT_FAIL;
	}
	if (inspect_mode_flag == 0x0F) { /*User Call HELP!*/
		seq_puts(s, "\n");
		seq_printf(s, "@ Short Test : %s\n",
			   "#echo Short > Inspect_mode ; #cat Inspect_mode");
		seq_printf(s, "@ Open  Test : %s\n",
			   "#echo Open  > Inspect_mode ; #cat Inspect_mode");
		seq_printf(s, "@ Noise Test : %s\n",
			   "#echo Noise > Inspect_mode ; #cat Inspect_mode");
		seq_printf(s, "@ All Test   : %s\n",
			   "#echo All   > Inspect_mode ; #cat Inspect_mode");
		seq_puts(s, "\n");
		seq_puts(
			s,
			"@ Set Inspect_mode Threshold by writing register :\n");
		seq_puts(
			s,
			"	Address    |  Threshold Item |    [31:16]    |    [15:0]\n");
		seq_puts(
			s,
			"	0x100074A0 |  Short Test     | High Boundary | Low Boundary\n");
		seq_puts(
			s,
			"	0x100074A4 |  Open Test      | High Boundary | Low Boundary\n");
		seq_puts(
			s,
			"	0x100074AC |  Noise Test     | High Boundary | Low Boundary\n");
		seq_puts(
			s,
			"	0x100074B0 |  Raw data       | High Boundary | Low Boundary\n");
		seq_puts(s, "\n");
		seq_puts(
			s,
			"Example : To set High Boundary = 0xFF ; Low Boundary = 0x11\n");
		seq_puts(s, "#echo register,w:x100074A4:x00FF0011 > debug\n");
		seq_puts(s, "\n");
		return true;
	}

	himax_int_enable(0); /* disable irq */
	// private_ts->in_self_test = 1;
	val = himax_chip_inspect_mode(s, v);
	// private_ts->in_self_test = 0;
	himax_int_enable(1);

	return ret;
}

static void *himax_inspect_mode_seq_start(struct seq_file *s, loff_t *pos)
{
	if (*pos >= 1)
		return NULL;

	return (void *)((unsigned long)*pos + 1);
}

static void *himax_inspect_mode_seq_next(struct seq_file *s, void *v,
					 loff_t *pos)
{
	return NULL;
}

static void himax_inspect_mode_seq_stop(struct seq_file *s, void *v)
{
}

static int himax_inspect_mode_seq_read(struct seq_file *s, void *v)
{
	size_t ret = 0;

	himax_inspect_mode(s, v);

	return ret;
}

static const struct seq_operations himax_inspect_mode_seq_ops = {
	.start = himax_inspect_mode_seq_start,
	.next = himax_inspect_mode_seq_next,
	.stop = himax_inspect_mode_seq_stop,
	.show = himax_inspect_mode_seq_read,
};

static int himax_inspect_mode_proc_open(struct inode *inode, struct file *file)
{
	return seq_open(file, &himax_inspect_mode_seq_ops);
};

static ssize_t himax_inspect_mode_write(struct file *filp,
					const char __user *buff, size_t len,
					loff_t *data)
{
	char buf[80];

	if (len >= 80) {
		I("%s: no command exceeds 80 chars.\n", __func__);
		return -EFAULT;
	}

	if (copy_from_user(buf, buff, len))
		return -EFAULT;

	if ((buf[0] == 's') || (buf[0] == 'S')) {
		inspect_mode_flag = 0x01;
		I("%s: Start to do Short_test.\n", __func__);
	} else if ((buf[0] == 'o') || (buf[0] == 'O')) {
		inspect_mode_flag = 0x02;
		I("%s: Start to do Open_test.\n", __func__);
	} else if ((buf[0] == 'n') || (buf[0] == 'N')) {
		inspect_mode_flag = 0x08;
		I("%s: Start to do Noise_test.\n", __func__);
	} else if ((buf[0] == 'a') || (buf[0] == 'A')) {
		inspect_mode_flag = 0x0B;
		I("%s: Start to do All_test.\n", __func__);
	} else if (buf[0] == 'h') {
		inspect_mode_flag = 0x0F;
		I("%s: User Call HELP! Lest's assist user to operate.\n",
		  __func__);
	} else {
		I("%s: Input cmd is incorrect!\n", __func__);
	}

	return len;
}

static const struct proc_ops himax_proc_inspect_mode_ops = {
	.proc_open = himax_inspect_mode_proc_open,
	.proc_read = seq_read,
	.proc_write = himax_inspect_mode_write,
	.proc_release = seq_release,
};
#endif

static ssize_t himax_GTS_read(struct file *file, char *buf, size_t len,
			      loff_t *pos)
{
	size_t count = 0;
	struct himax_ts_data *ts = private_ts;
	char *temp_buf = NULL;

	if (!HX_PROC_SEND_FLAG) {
		temp_buf = kcalloc(len, sizeof(char), GFP_KERNEL);
		if (temp_buf != NULL) {
			count = snprintf(temp_buf, PAGE_SIZE, "%d\n",
					 ts->GTS_range);

			if (copy_to_user(buf, temp_buf, len))
				I("%s, here:%d\n", __func__, __LINE__);

			kfree(temp_buf);
			HX_PROC_SEND_FLAG = 1;
		} else {
			E("%s, Failed to allocate memory\n", __func__);
		}
	} else {
		HX_PROC_SEND_FLAG = 0;
	}

	return count;
}

static ssize_t himax_GTS_write(struct file *file, const char *buff, size_t len,
			       loff_t *pos)
{
	struct himax_ts_data *ts = private_ts;
	char buf[80] = { 0 };

	if (len >= 80) {
		I("%s: no command exceeds 80 chars.\n", __func__);
		return -EFAULT;
	}

	if (copy_from_user(buf, buff, len))
		return -EFAULT;

	if (buf[0] == '0') {
		ts->GTS_range = 0;
		I("%s: Ghost point protection disable\n", __func__);
	} else if ((buf[0] > '0') && (buf[0] < '9')) {
		ts->GTS_range = buf[0] - '0';
		I("%s: Ghost point protection enable\n", __func__);
	} else {
		return -EINVAL;
	}
	return len;
}

static const struct proc_ops himax_proc_GTS_ops = {
	.proc_read = himax_GTS_read,
	.proc_write = himax_GTS_write,
};
#if (HX_SMART_WAKEUP == 0x01)
static ssize_t himax_SMWP_read(struct file *file, char *buf, size_t len,
			       loff_t *pos)
{
	size_t count = 0;
	struct himax_ts_data *ts = private_ts;
	char *temp_buf = NULL;

	if (!HX_PROC_SEND_FLAG) {
		temp_buf = kcalloc(len, sizeof(char), GFP_KERNEL);
		if (temp_buf != NULL) {
			count = snprintf(temp_buf, PAGE_SIZE, "%d\n",
					 ts->SMWP_enable);

			if (copy_to_user(buf, temp_buf, len))
				I("%s, here:%d\n", __func__, __LINE__);

			kfree(temp_buf);
			HX_PROC_SEND_FLAG = 1;
		} else {
			E("%s, Failed to allocate memory\n", __func__);
		}
	} else {
		HX_PROC_SEND_FLAG = 0;
	}

	return count;
}

static ssize_t himax_SMWP_write(struct file *file, const char *buff, size_t len,
				loff_t *pos)
{
	struct himax_ts_data *ts = private_ts;
	char buf[80] = { 0 };

	if (len >= 80) {
		I("%s: no command exceeds 80 chars.\n", __func__);
		return -EFAULT;
	}

	if (copy_from_user(buf, buff, len))
		return -EFAULT;

	if (buf[0] == '0')
		ts->SMWP_enable = 0;
	else if (buf[0] == '1')
		ts->SMWP_enable = 1;
	else
		return -EINVAL;

	himax_mcu_set_SMWP_enable(ts->SMWP_enable, ts->suspended);
	HX_SMWP_EN = ts->SMWP_enable;
	I("%s: SMART_WAKEUP_enable = %d.\n", __func__, HX_SMWP_EN);
	return len;
}

static const struct file_operations himax_proc_SMWP_ops = {
	.owner = THIS_MODULE,
	.read = himax_SMWP_read,
	.write = himax_SMWP_write,
};

static ssize_t himax_GESTURE_read(struct file *file, char *buf, size_t len,
				  loff_t *pos)
{
	struct himax_ts_data *ts = private_ts;
	int i = 0;
	size_t ret = 0;
	char *temp_buf = NULL;

	if (!HX_PROC_SEND_FLAG) {
		temp_buf = kcalloc(len, sizeof(char), GFP_KERNEL);
		if (temp_buf != NULL) {
			for (i = 0; i < GEST_SUP_NUM; i++)
				ret += snprintf(temp_buf + ret, len - ret,
						"ges_en[%d]=%d\n", i,
						ts->gesture_cust_en[i]);

			if (copy_to_user(buf, temp_buf, len))
				I("%s, here:%d\n", __func__, __LINE__);

			kfree(temp_buf);
			HX_PROC_SEND_FLAG = 1;
		} else {
			E("%s, Failed to allocate memory\n", __func__);
		}
	} else {
		HX_PROC_SEND_FLAG = 0;
		ret = 0;
	}

	return ret;
}

static ssize_t himax_GESTURE_write(struct file *file, const char *buff,
				   size_t len, loff_t *pos)
{
	struct himax_ts_data *ts = private_ts;
	int i = 0;
	int j = 0;
	char buf[80] = { 0 };

	if (len >= 80) {
		I("%s: no command exceeds 80 chars.\n", __func__);
		return -EFAULT;
	}

	if (copy_from_user(buf, buff, len))
		return -EFAULT;

	I("himax_GESTURE_store= %s, len = %d\n", buf, (int)len);

	for (i = 0; i < len; i++) {
		if (buf[i] == '0' && j < GEST_SUP_NUM) {
			ts->gesture_cust_en[j] = 0;
			I("gesture en[%d]=%d\n", j, ts->gesture_cust_en[j]);
			j++;
		} else if (buf[i] == '1' && j < GEST_SUP_NUM) {
			ts->gesture_cust_en[j] = 1;
			I("gesture en[%d]=%d\n", j, ts->gesture_cust_en[j]);
			j++;
		} else
			I("Not 0/1 or >=GEST_SUP_NUM : buf[%d] = %c\n", i,
			  buf[i]);
	}

	return len;
}

static const struct file_operations himax_proc_Gesture_ops = {
	.owner = THIS_MODULE,
	.read = himax_GESTURE_read,
	.write = himax_GESTURE_write,
};

#endif

int himax_common_proc_init(void)
{
	himax_touch_proc_dir = proc_mkdir(HIMAX_PROC_TOUCH_FOLDER, NULL);

	if (himax_touch_proc_dir == NULL) {
		E(" %s: himax_touch_proc_dir file create failed!\n", __func__);
		return -ENOMEM;
	}

	himax_proc_self_test_file =
		proc_create(HIMAX_PROC_SELF_TEST_FILE, 0444,himax_touch_proc_dir, &himax_proc_self_test_ops);
	if (himax_proc_self_test_file == NULL) {
		E(" %s: proc self_test file create failed!\n", __func__);
		goto fail_1;
	}

#if (HX_SMART_WAKEUP == 0x01)
	himax_proc_SMWP_file =
		proc_create(HIMAX_PROC_SMWP_FILE, 0666, himax_touch_proc_dir,
			    &himax_proc_SMWP_ops);

	if (himax_proc_SMWP_file == NULL) {
		E(" %s: proc SMWP file create failed!\n", __func__);
		goto fail_2;
	}

	himax_proc_GESTURE_file =
		proc_create(HIMAX_PROC_GESTURE_FILE, 0666, himax_touch_proc_dir,
			    &himax_proc_Gesture_ops);

	if (himax_proc_GESTURE_file == NULL) {
		E(" %s: proc GESTURE file create failed!\n", __func__);
		goto fail_3;
	}
#endif

	himax_proc_WPBPlock_node_file =
		proc_create(HIMAX_PROC_WP_BP_LOCK_FILE, 0444,
			    himax_touch_proc_dir,
			    &himax_proc_WPBPlock_node_ops);
	if (himax_proc_WPBPlock_node_file == NULL) {
		E(" %s: proc BPlock file create failed!\n", __func__);
		goto fail_4;
	}

	himax_proc_fail_det_file =
		proc_create(HIMAX_PROC_FAIL_DET_FILE, 0444,
			    himax_touch_proc_dir, &himax_proc_fail_det_ops);
	if (himax_proc_fail_det_file == NULL) {
		E(" %s: proc fail det file create failed!\n", __func__);
		goto fail_5;
	}

#if (HX_TP_INSPECT_MODE == 0x01)
	himax_proc_INSPECT_MODE_file =
		proc_create(HIMAX_PROC_INSPECT_MODE_FILE, 0666,
			    himax_touch_proc_dir, &himax_proc_inspect_mode_ops);

	if (himax_proc_INSPECT_MODE_file == NULL) {
		E(" %s: proc INSPECT_MODE file create failed!\n", __func__);
		goto fail_6;
	}
#endif
	himax_proc_GTS_file =
		proc_create(HIMAX_PROC_GTS_FILE, 0666, himax_touch_proc_dir,
			    &himax_proc_GTS_ops);

	if (himax_proc_GTS_file == NULL) {
		E(" %s: proc GTS file create failed!\n", __func__);
		goto fail_7;
	}

	return 0;
fail_7:
#if (HX_TP_INSPECT_MODE == 0x01)
	remove_proc_entry(HIMAX_PROC_INSPECT_MODE_FILE, himax_touch_proc_dir);
fail_6:
#endif
	remove_proc_entry(HIMAX_PROC_FAIL_DET_FILE, himax_touch_proc_dir);
fail_5:
	remove_proc_entry(HIMAX_PROC_WP_BP_LOCK_FILE, himax_touch_proc_dir);
fail_4:
#if (HX_SMART_WAKEUP == 0x01)
	remove_proc_entry(HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir);
fail_3:
	remove_proc_entry(HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir);
fail_2:
#endif
	remove_proc_entry(HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir);
fail_1:
	return -ENOMEM;
}

void himax_common_proc_deinit(void)
{
	remove_proc_entry(HIMAX_PROC_GTS_FILE, himax_touch_proc_dir);
#if (HX_TP_INSPECT_MODE == 0x01)
	remove_proc_entry(HIMAX_PROC_INSPECT_MODE_FILE, himax_touch_proc_dir);
#endif
	remove_proc_entry(HIMAX_PROC_FAIL_DET_FILE, himax_touch_proc_dir);
	remove_proc_entry(HIMAX_PROC_WP_BP_LOCK_FILE, himax_touch_proc_dir);
#if (HX_SMART_WAKEUP == 0x01)
	remove_proc_entry(HIMAX_PROC_GESTURE_FILE, himax_touch_proc_dir);
	remove_proc_entry(HIMAX_PROC_SMWP_FILE, himax_touch_proc_dir);
#endif
	remove_proc_entry(HIMAX_PROC_SELF_TEST_FILE, himax_touch_proc_dir);
	remove_proc_entry(HIMAX_PROC_TOUCH_FOLDER, NULL);
}

void himax_parse_assign_cmd(uint32_t addr, uint8_t *cmd, int len)
{
	/*I("%s: Entering!\n", __func__);*/
	switch (len) {
	case 1:
		cmd[0] = addr;
		/*I("%s: cmd[0] = 0x%02X\n", __func__, cmd[0]);*/
		break;
	case 2:
		cmd[0] = addr % 0x100;
		cmd[1] = (addr >> 8) % 0x100;
		/*I("%s: cmd[0] = 0x%02X,cmd[1] = 0x%02X\n",*/
		/*	__func__, cmd[0], cmd[1]);*/
		break;
	case 4:
		cmd[0] = addr % 0x100;
		cmd[1] = (addr >> 8) % 0x100;
		cmd[2] = (addr >> 16) % 0x100;
		cmd[3] = addr / 0x1000000;
		/*  I("%s: cmd[0] = 0x%02X,cmd[1] = 0x%02X,*/
		/*cmd[2] = 0x%02X,cmd[3] = 0x%02X\n", */
		/* __func__, cmd[0], cmd[1], cmd[2], cmd[3]);*/
		break;
	default:
		E("%s: input length fault,len = %d!\n", __func__, len);
	}
}
EXPORT_SYMBOL(himax_parse_assign_cmd);

int himax_input_register(struct himax_ts_data *ts)
{
	int ret = 0;
#if (HX_SMART_WAKEUP == 0x01)
	int i = 0;
#endif

	ret = himax_dev_set(ts);

	if (ret < 0) {
		I("%s, input device register fail!\n", __func__);
		ret = INPUT_REGISTER_FAIL;
		goto input_device_fail;
	}

	set_bit(EV_SYN, ts->input_dev->evbit);
	set_bit(EV_ABS, ts->input_dev->evbit);
	set_bit(EV_KEY, ts->input_dev->evbit);
	set_bit(KEY_BACK, ts->input_dev->keybit);
	set_bit(KEY_HOME, ts->input_dev->keybit);
	set_bit(KEY_MENU, ts->input_dev->keybit);
	set_bit(KEY_SEARCH, ts->input_dev->keybit);

#if (HX_SMART_WAKEUP == 0x01)
	for (i = 0; i < GEST_SUP_NUM; i++)
		set_bit(gest_key_def[i], ts->input_dev->keybit);
#elif defined(CONFIG_TOUCHSCREEN_HIMAX_INSPECT)
	set_bit(KEY_POWER, ts->input_dev->keybit);
#endif
	set_bit(BTN_TOUCH, ts->input_dev->keybit);
	set_bit(KEY_APPSELECT, ts->input_dev->keybit);
	set_bit(INPUT_PROP_DIRECT, ts->input_dev->propbit);
#if (HX_PROTOCOL_A == 0x01)
	/*ts->input_dev->mtsize = ts->nFinger_support;*/
	input_set_abs_params(ts->input_dev, ABS_MT_TRACKING_ID, 0, 3, 0, 0);
#else
	set_bit(MT_TOOL_FINGER, ts->input_dev->keybit);
#if (HX_PROTOCOL_B_3PA == 0x01)
	input_mt_init_slots(ts->input_dev, ts->nFinger_support,
			    INPUT_MT_DIRECT);
#else
	input_mt_init_slots(ts->input_dev, ts->nFinger_support);
#endif
#endif
	I("%s: mix_x %d, max_x %d, min_y %d, max_y %d\n", __func__,
	  ts->pdata->abs_x_min, ts->pdata->abs_x_max, ts->pdata->abs_y_min,
	  ts->pdata->abs_y_max);
	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_X,
			     ts->pdata->abs_x_min, ts->pdata->abs_x_max,
			     ts->pdata->abs_x_fuzz, 0);
	input_set_abs_params(ts->input_dev, ABS_MT_POSITION_Y,
			     ts->pdata->abs_y_min, ts->pdata->abs_y_max,
			     ts->pdata->abs_y_fuzz, 0);
	input_set_abs_params(ts->input_dev, ABS_MT_TOUCH_MAJOR,
			     ts->pdata->abs_pressure_min,
			     ts->pdata->abs_pressure_max,
			     ts->pdata->abs_pressure_fuzz, 0);
#if (HX_PROTOCOL_A == 0x00)
	input_set_abs_params(ts->input_dev, ABS_MT_PRESSURE,
			     ts->pdata->abs_pressure_min,
			     ts->pdata->abs_pressure_max,
			     ts->pdata->abs_pressure_fuzz, 0);
	input_set_abs_params(ts->input_dev, ABS_MT_WIDTH_MAJOR,
			     ts->pdata->abs_width_min, ts->pdata->abs_width_max,
			     ts->pdata->abs_pressure_fuzz, 0);
#endif
	/*	input_set_abs_params(ts->input_dev, ABS_MT_AMPLITUDE, 0,*/
	/*			((ts->pdata->abs_pressure_max << 16)*/
	/*			| ts->pdata->abs_width_max),*/
	/*			0, 0);*/
	/*	input_set_abs_params(ts->input_dev, ABS_MT_POSITION,*/
	/*			0, (BIT(31)*/
	/*			| (ts->pdata->abs_x_max << 16)*/
	/*			| ts->pdata->abs_y_max),*/
	/*			0, 0);*/

	if (himax_input_register_device(ts->input_dev) == 0) {
		ret = NO_ERR;
	} else {
		E("%s: input register fail\n", __func__);
		ret = INPUT_REGISTER_FAIL;
		goto input_device_fail;
	}

input_device_fail:
	return ret;
}
EXPORT_SYMBOL(himax_input_register);

static void himax_calcDataSize(void)
{
	struct himax_ts_data *ts_data = private_ts;

	ts_data->x_channel = ic_data->HX_RX_NUM;
	ts_data->y_channel = ic_data->HX_TX_NUM;
	ts_data->nFinger_support = ic_data->HX_MAX_PT;

	ts_data->coord_data_size = 4 * ts_data->nFinger_support;
	ts_data->area_data_size = ((ts_data->nFinger_support / 4) +
				   (ts_data->nFinger_support % 4 ? 1 : 0)) *
				  4;
	ts_data->coordInfoSize =
		ts_data->coord_data_size + ts_data->area_data_size + 4;
	ts_data->raw_data_frame_size = 128 - ts_data->coord_data_size -
				       ts_data->area_data_size - 4 - 4 - 1;

	if (ts_data->raw_data_frame_size == 0) {
		E("%s: could NOT calculate!\n", __func__);
		return;
	}

	I("%s: coord_dsz:%d,area_dsz:%d,raw_data_fsz:%d", __func__,
	  ts_data->coord_data_size, ts_data->area_data_size,
	  ts_data->raw_data_frame_size);
}

static void calculate_point_number(void)
{
	HX_TOUCH_INFO_POINT_CNT = ic_data->HX_MAX_PT * 4;

	if ((ic_data->HX_MAX_PT % 4) == 0)
		HX_TOUCH_INFO_POINT_CNT += (ic_data->HX_MAX_PT / 4) * 4;
	else
		HX_TOUCH_INFO_POINT_CNT += ((ic_data->HX_MAX_PT / 4) + 1) * 4;
}

#if (HX_BOOT_UPGRADE == 0x01)
/*-------------------------------------------------------------------------
 *
 *	Create: Unknown
 *
 *	Description: Read FW_VER and CFG_VER value from FW file and compare with
 *		         FW/CFG version from MCU.
 *	Parameters: void
 *
 *	Returns: int (0 need update/ 1 no need update)
 *
 *	Side effects: None
 */
static int himax_auto_update_check(void)
{
	int32_t ret;

	if ((ic_data->vendor_touch_cfg_ver > 0x80) ||
	    (ic_data->vendor_display_cfg_ver > 0x80)) {
		I("%s: Test FW, Need to update\n", __func__);
		ret = 0;
		return ret;
	}

	if (himax_mcu_fw_ver_bin() == NO_ERR) {
		if ((ic_data->vendor_arch_ver < g_i_FW_VER) ||
		    (ic_data->vendor_config_ver < g_i_CFG_VER)) {
			I("%s: FW BIN is newer version, Need to update\n",
			  __func__);
			ret = 0;
		} else if ((ic_data->vendor_arch_ver == g_i_FW_VER) &&
			   (ic_data->vendor_config_ver == g_i_CFG_VER)) {
			if (himax_mcu_flash_lastdata_check_with_bin(
				    FW_SIZE_128k) == 1) {
				W("%s: Flash FW is different from BIN, Need update\n",
				  __func__);
				ret = 0;
			} else {
				I("%s: Flash FW is same with BIN, No need update!\n",
				  __func__);
				ret = 1;
			}
		} else {
			I("%s: Flash FW is newer version, No need update!\n",
			  __func__);
			ret = 1;
		}
	} else {
		E("%s: FW bin fail!\n", __func__);
		ret = 1;
	}

	return ret;
}

static int i_get_FW(void)
{
	int ret = -1;
	int result = NO_ERR;

	I("%s: file name = %s\n", __func__, BOOT_UPGRADE_FWNAME);
	ret = request_firmware(&hxfw, BOOT_UPGRADE_FWNAME, private_ts->dev);
	if (ret < 0) {
#if defined(__EMBEDDED_FW__)
		hxfw = &g_embedded_fw;
		I("%s: Not find FW in userspace, use embedded FW(size:%zu)",
		  __func__, g_embedded_fw.size);
#else
		E("%s,%d: error code = %d\n", __func__, __LINE__, ret);
		return OPEN_FILE_FAIL;
#endif
	}

	return result;
}

static int i_update_FW(void)
{
	int upgrade_times = 0;
	int8_t ret = 0;
	int8_t result = 0;
	char tmp_buf[64] = { 0 };

	himax_int_enable(0);

update_retry:

	if (hxfw->size == FW_SIZE_128k)
		ret = himax_mcu_fts_ctpm_fw_upgrade_with_sys_fs_128k(
			(unsigned char *)hxfw->data, hxfw->size, false);

	if (ret == 0) {
		upgrade_times++;
		E("%s: TP upgrade error, upgrade_times = %d\n", __func__,
		  upgrade_times);

		if (upgrade_times < 3)
			goto update_retry;
		else
			result = -1;

	} else {
		himax_mcu_reload_disable(0);
		himax_mcu_power_on_init();
		himax_mcu_read_FW_ver();
		himax_mcu_touch_information();
		result = 1; /*upgrade success*/
		I("%s: TP upgrade OK\n", __func__);
	}

#if (HX_WPBP_ENABLE == 0x01)
	himax_enable_flash_protected_mode();
#endif
	himax_mcu_read_event_stack(tmp_buf, 56);
	himax_int_enable(1);
	return result;
}
#endif
/*
 *static int himax_loadSensorConfig(struct himax_i2c_platform_data *pdata)
 *{
 *	I("%s: initialization complete\n", __func__);
 *	return NO_ERR;
 *}
 */
#if (HX_EXCP_RECOVERY == 0x01)
static void himax_excp_hw_reset(void)
{
	if (g_ts_dbg != 0)
		I("%s: Entering\n", __func__);

	I("%s: START EXCEPTION Reset\n", __func__);

	if (private_ts->in_self_test == 1) {
		I("%s: In self test, not TP EXCEPTION Reset\n", __func__);
		return;
	}
	himax_mcu_excp_ic_reset();

	I("%s: END EXCEPTION Reset\n", __func__);
}
#endif

#if (HX_SMART_WAKEUP == 0x01)
#if (HX_GESTURE_TRACK == 0x01)
static void gest_pt_log_coordinate(int rx, int tx)
{
	/*driver report x y with range 0 - 255 , we scale it up to x/y pixel*/
	gest_pt_x[gest_pt_cnt] = rx * (ic_data->HX_X_RES) / 255;
	gest_pt_y[gest_pt_cnt] = tx * (ic_data->HX_Y_RES) / 255;
}
#endif
static int himax_wake_event_parse(struct himax_ts_data *ts, int ts_status)
{
	uint8_t *buf = wake_event_buffer;
#if (HX_GESTURE_TRACK == 0x01)
	int tmp_max_x = 0x00;
	int tmp_min_x = 0xFFFF;
	int tmp_max_y = 0x00;
	int tmp_min_y = 0xFFFF;
	int gest_len;
#endif
	int i = 0, check_FC = 0, ret;
	int j = 0, gesture_pos = 0, gesture_flag = 0;

	if (g_ts_dbg != 0)
		I("%s: Entering!, ts_status=%d\n", __func__, ts_status);

	if (buf == NULL) {
		ret = -ENOMEM;
		goto END;
	}

	memcpy(buf, hx_touch_data->hx_event_buf, hx_touch_data->event_size);

	for (i = 0; i < GEST_PTLG_ID_LEN; i++) {
		for (j = 0; j < GEST_SUP_NUM; j++) {
			if (buf[i] == gest_event[j]) {
				gesture_flag = buf[i];
				gesture_pos = j;
				break;
			}
		}
		I("0x%2.2X ", buf[i]);
		if (buf[i] == gesture_flag) {
			check_FC++;
		} else {
			I("ID START at %x , value = 0x%2X skip the event\n", i,
			  buf[i]);
			break;
		}
	}

	I("Himax gesture_flag= %x\n", gesture_flag);
	I("Himax check_FC is %d\n", check_FC);

	if (check_FC != GEST_PTLG_ID_LEN) {
		ret = 0;
		goto END;
	}

	if (buf[GEST_PTLG_ID_LEN] != GEST_PTLG_HDR_ID1 ||
	    buf[GEST_PTLG_ID_LEN + 1] != GEST_PTLG_HDR_ID2) {
		ret = 0;
		goto END;
	}

#if (HX_GESTURE_TRACK == 0x01)

	if (buf[GEST_PTLG_ID_LEN] == GEST_PTLG_HDR_ID1 &&
	    buf[GEST_PTLG_ID_LEN + 1] == GEST_PTLG_HDR_ID2) {
		gest_len = buf[GEST_PTLG_ID_LEN + 2];
		I("gest_len = %d\n", gest_len);
		i = 0;
		gest_pt_cnt = 0;
		I("gest doornidate start\n %s", __func__);

		while (i < (gest_len + 1) / 2) {
			gest_pt_log_coordinate(
				buf[GEST_PTLG_ID_LEN + 4 + i * 2],
				buf[GEST_PTLG_ID_LEN + 4 + i * 2 + 1]);
			i++;
			I("gest_pt_x[%d]=%d,gest_pt_y[%d]=%d\n", gest_pt_cnt,
			  gest_pt_x[gest_pt_cnt], gest_pt_cnt,
			  gest_pt_y[gest_pt_cnt]);
			gest_pt_cnt += 1;
		}

		if (gest_pt_cnt) {
			for (i = 0; i < gest_pt_cnt; i++) {
				if (tmp_max_x < gest_pt_x[i])
					tmp_max_x = gest_pt_x[i];
				if (tmp_min_x > gest_pt_x[i])
					tmp_min_x = gest_pt_x[i];
				if (tmp_max_y < gest_pt_y[i])
					tmp_max_y = gest_pt_y[i];
				if (tmp_min_y > gest_pt_y[i])
					tmp_min_y = gest_pt_y[i];
			}

			I("gest_point x_min=%d,x_max=%d,y_min=%d,y_max=%d\n",
			  tmp_min_x, tmp_max_x, tmp_min_y, tmp_max_y);

			gest_start_x = gest_pt_x[0];
			hx_gesture_coor[0] = gest_start_x;
			gest_start_y = gest_pt_y[0];
			hx_gesture_coor[1] = gest_start_y;
			gest_end_x = gest_pt_x[gest_pt_cnt - 1];
			hx_gesture_coor[2] = gest_end_x;
			gest_end_y = gest_pt_y[gest_pt_cnt - 1];
			hx_gesture_coor[3] = gest_end_y;
			gest_width = tmp_max_x - tmp_min_x;
			hx_gesture_coor[4] = gest_width;
			gest_height = tmp_max_y - tmp_min_y;
			hx_gesture_coor[5] = gest_height;
			gest_mid_x = (tmp_max_x + tmp_min_x) / 2;
			hx_gesture_coor[6] = gest_mid_x;
			gest_mid_y = (tmp_max_y + tmp_min_y) / 2;
			hx_gesture_coor[7] = gest_mid_y;
			/*gest_up_x*/
			hx_gesture_coor[8] = gest_mid_x;
			/*gest_up_y*/
			hx_gesture_coor[9] = gest_mid_y - gest_height / 2;
			/*gest_down_x*/
			hx_gesture_coor[10] = gest_mid_x;
			/*gest_down_y*/
			hx_gesture_coor[11] = gest_mid_y + gest_height / 2;
			/*gest_left_x*/
			hx_gesture_coor[12] = gest_mid_x - gest_width / 2;
			/*gest_left_y*/
			hx_gesture_coor[13] = gest_mid_y;
			/*gest_right_x*/
			hx_gesture_coor[14] = gest_mid_x + gest_width / 2;
			/*gest_right_y*/
			hx_gesture_coor[15] = gest_mid_y;
		}
	}

#endif

	if (!ts->gesture_cust_en[gesture_pos]) {
		I("%s NOT report key [%d] = %d\n", __func__, gesture_pos,
		  gest_key_def[gesture_pos]);
		g_target_report_data->SMWP_event_chk = 0;
		ret = 0;
	} else {
		g_target_report_data->SMWP_event_chk =
			gest_key_def[gesture_pos];
		ret = gesture_pos;
	}
END:
	return ret;
}

static void himax_wake_event_report(void)
{
	int KEY_EVENT = g_target_report_data->SMWP_event_chk;

	if (g_ts_dbg != 0)
		I("%s: Entering!\n", __func__);

	if (KEY_EVENT) {
		I("%s SMART WAKEUP KEY event %d press\n", __func__, KEY_EVENT);
		input_report_key(private_ts->input_dev, KEY_EVENT, 1);
		input_sync(private_ts->input_dev);
		I("%s SMART WAKEUP KEY event %d release\n", __func__,
		  KEY_EVENT);
		input_report_key(private_ts->input_dev, KEY_EVENT, 0);
		input_sync(private_ts->input_dev);
#if (HX_GESTURE_TRACK == 0x01)
		I("gest_start_x=%d,start_y=%d,end_x=%d,end_y=%d\n",
		  gest_start_x, gest_start_y, gest_end_x, gest_end_y);
		I("gest_width=%d,height=%d,mid_x=%d,mid_y=%d\n", gest_width,
		  gest_height, gest_mid_x, gest_mid_y);
		I("gest_up_x=%d,up_y=%d,down_x=%d,down_y=%d\n",
		  hx_gesture_coor[8], hx_gesture_coor[9], hx_gesture_coor[10],
		  hx_gesture_coor[11]);
		I("gest_left_x=%d,left_y=%d,right_x=%d,right_y=%d\n",
		  hx_gesture_coor[12], hx_gesture_coor[13], hx_gesture_coor[14],
		  hx_gesture_coor[15]);
#endif
		g_target_report_data->SMWP_event_chk = 0;
	}
}

#endif

int himax_report_data_init(void)
{
	if (hx_touch_data->hx_coord_buf != NULL) {
		kfree(hx_touch_data->hx_coord_buf);
		hx_touch_data->hx_coord_buf = NULL;
	}
	if (hx_touch_data->hx_rawdata_buf != NULL) {
		kfree(hx_touch_data->hx_rawdata_buf);
		hx_touch_data->hx_rawdata_buf = NULL;
	}

#if (HX_SMART_WAKEUP == 0x01)
	hx_touch_data->event_size = himax_mcu_get_touch_data_size();

	if (hx_touch_data->hx_event_buf != NULL) {
		kfree(hx_touch_data->hx_event_buf);
		hx_touch_data->hx_event_buf = NULL;
	}

	if (wake_event_buffer != NULL) {
		kfree(wake_event_buffer);
		wake_event_buffer = NULL;
	}

#endif
	hx_touch_data->touch_all_size = himax_mcu_get_touch_data_size();
	hx_touch_data->raw_cnt_max = ic_data->HX_MAX_PT / 4;
	hx_touch_data->raw_cnt_rmd = ic_data->HX_MAX_PT % 4;
	/* more than 4 fingers */
	if (hx_touch_data->raw_cnt_rmd != 0x00) {
		hx_touch_data->rawdata_size =
			himax_mcu_cal_data_len(hx_touch_data->raw_cnt_rmd,
					       ic_data->HX_MAX_PT,
					       hx_touch_data->raw_cnt_max);

		hx_touch_data->touch_info_size =
			(ic_data->HX_MAX_PT + hx_touch_data->raw_cnt_max + 2) *
			4;
	} else { /* less than 4 fingers */
		hx_touch_data->rawdata_size =
			himax_mcu_cal_data_len(hx_touch_data->raw_cnt_rmd,
					       ic_data->HX_MAX_PT,
					       hx_touch_data->raw_cnt_max);

		hx_touch_data->touch_info_size =
			(ic_data->HX_MAX_PT + hx_touch_data->raw_cnt_max + 1) *
			4;
	}
	if ((ic_data->HX_TX_NUM * ic_data->HX_RX_NUM + ic_data->HX_TX_NUM +
	     ic_data->HX_RX_NUM) %
		    hx_touch_data->rawdata_size ==
	    0)
		hx_touch_data->rawdata_frame_size =
			(ic_data->HX_TX_NUM * ic_data->HX_RX_NUM +
			 ic_data->HX_TX_NUM + ic_data->HX_RX_NUM) /
			hx_touch_data->rawdata_size;
	else
		hx_touch_data->rawdata_frame_size =
			(ic_data->HX_TX_NUM * ic_data->HX_RX_NUM +
			 ic_data->HX_TX_NUM + ic_data->HX_RX_NUM) /
				hx_touch_data->rawdata_size +
			1;

	I("%s:rawdata_fsz = %d,HX_MAX_PT:%d,hx_raw_cnt_max:%d\n", __func__,
	  hx_touch_data->rawdata_frame_size, ic_data->HX_MAX_PT,
	  hx_touch_data->raw_cnt_max);
	I("%s:hx_raw_cnt_rmd:%d,g_hx_rawdata_size:%d,touch_info_size:%d\n",
	  __func__, hx_touch_data->raw_cnt_rmd, hx_touch_data->rawdata_size,
	  hx_touch_data->touch_info_size);

	hx_touch_data->hx_coord_buf = kzalloc(
		sizeof(uint8_t) * (hx_touch_data->touch_info_size), GFP_KERNEL);

	if (hx_touch_data->hx_coord_buf == NULL)
		goto mem_alloc_fail_coord_buf;

#if (HX_SMART_WAKEUP == 0x01)
	wake_event_buffer =
		kcalloc(hx_touch_data->event_size, sizeof(uint8_t), GFP_KERNEL);
	if (wake_event_buffer == NULL)
		goto mem_alloc_fail_smwp;

	hx_touch_data->hx_event_buf = kzalloc(
		sizeof(uint8_t) * (hx_touch_data->event_size), GFP_KERNEL);
	if (hx_touch_data->hx_event_buf == NULL)
		goto mem_alloc_fail_event_buf;
#endif

	hx_touch_data->hx_rawdata_buf =
		kzalloc(sizeof(uint8_t) * (hx_touch_data->touch_all_size -
					   hx_touch_data->touch_info_size),
			GFP_KERNEL);
	if (hx_touch_data->hx_rawdata_buf == NULL)
		goto mem_alloc_fail_rawdata_buf;

	if (g_target_report_data == NULL) {
		g_target_report_data = kzalloc(
			sizeof(struct himax_target_report_data), GFP_KERNEL);
		if (g_target_report_data == NULL)
			goto mem_alloc_fail_report_data;

		g_target_report_data->x =
			kzalloc(sizeof(int) * (ic_data->HX_MAX_PT), GFP_KERNEL);
		if (g_target_report_data->x == NULL)
			goto mem_alloc_fail_report_data_x;

		g_target_report_data->y =
			kzalloc(sizeof(int) * (ic_data->HX_MAX_PT), GFP_KERNEL);
		if (g_target_report_data->y == NULL)
			goto mem_alloc_fail_report_data_y;

		g_target_report_data->w =
			kzalloc(sizeof(int) * (ic_data->HX_MAX_PT), GFP_KERNEL);
		if (g_target_report_data->w == NULL)
			goto mem_alloc_fail_report_data_w;

		g_target_report_data->finger_id =
			kzalloc(sizeof(int) * (ic_data->HX_MAX_PT), GFP_KERNEL);
		if (g_target_report_data->finger_id == NULL)
			goto mem_alloc_fail_report_data_fid;
	}
	if (fixed_point_label == NULL) {
		fixed_point_label = kzalloc(
			sizeof(struct himax_target_report_data), GFP_KERNEL);
		if (fixed_point_label == NULL)
			goto mem_alloc_fail_pre_report_data;

		fixed_point_label->x =
			kzalloc(sizeof(int) * (ic_data->HX_MAX_PT), GFP_KERNEL);
		if (fixed_point_label->x == NULL)
			goto mem_alloc_fail_pre_report_data_x;

		fixed_point_label->y =
			kzalloc(sizeof(int) * (ic_data->HX_MAX_PT), GFP_KERNEL);
		if (fixed_point_label->y == NULL)
			goto mem_alloc_fail_pre_report_data_y;

		fixed_point_label->finger_id =
			kzalloc(sizeof(int) * (ic_data->HX_MAX_PT), GFP_KERNEL);
		if (fixed_point_label->finger_id == NULL)
			goto mem_alloc_fail_pre_report_data_fid;
		fixed_point_label->fpt_cnt =
			kzalloc(sizeof(int) * (ic_data->HX_MAX_PT), GFP_KERNEL);
		if (fixed_point_label->fpt_cnt == NULL)
			goto mem_alloc_fail_pre_report_data_fpt_cnt;
	}
	memset(fixed_point_label->x, 0xFFFF, ic_data->HX_MAX_PT);
	memset(fixed_point_label->y, 0xFFFF, ic_data->HX_MAX_PT);
	return NO_ERR;
mem_alloc_fail_pre_report_data_fpt_cnt:
	kfree(fixed_point_label->finger_id);
	fixed_point_label->finger_id = NULL;
mem_alloc_fail_pre_report_data_fid:
	kfree(fixed_point_label->y);
	fixed_point_label->y = NULL;
mem_alloc_fail_pre_report_data_y:
	kfree(fixed_point_label->x);
	fixed_point_label->x = NULL;
mem_alloc_fail_pre_report_data_x:
	kfree(fixed_point_label);
	fixed_point_label = NULL;
mem_alloc_fail_pre_report_data:
	kfree(g_target_report_data->finger_id);
	g_target_report_data->finger_id = NULL;
mem_alloc_fail_report_data_fid:
	kfree(g_target_report_data->w);
	g_target_report_data->w = NULL;
mem_alloc_fail_report_data_w:
	kfree(g_target_report_data->y);
	g_target_report_data->y = NULL;
mem_alloc_fail_report_data_y:
	kfree(g_target_report_data->x);
	g_target_report_data->x = NULL;
mem_alloc_fail_report_data_x:
	kfree(g_target_report_data);
	g_target_report_data = NULL;
mem_alloc_fail_report_data:
	kfree(hx_touch_data->hx_rawdata_buf);
	hx_touch_data->hx_rawdata_buf = NULL;
#if (HX_SMART_WAKEUP == 0x01)
	kfree(hx_touch_data->hx_event_buf);
	hx_touch_data->hx_event_buf = NULL;
mem_alloc_fail_event_buf:
	kfree(wake_event_buffer);
	wake_event_buffer = NULL;
mem_alloc_fail_smwp:
#endif
mem_alloc_fail_rawdata_buf:
	kfree(hx_touch_data->hx_coord_buf);
	hx_touch_data->hx_coord_buf = NULL;
mem_alloc_fail_coord_buf:

	E("%s: Failed to allocate memory\n", __func__);
	return MEM_ALLOC_FAIL;
}
EXPORT_SYMBOL(himax_report_data_init);

void himax_report_data_deinit(void)
{
	kfree(g_target_report_data->finger_id);
	g_target_report_data->finger_id = NULL;
	kfree(g_target_report_data->w);
	g_target_report_data->w = NULL;
	kfree(g_target_report_data->y);
	g_target_report_data->y = NULL;
	kfree(g_target_report_data->x);
	g_target_report_data->x = NULL;
	kfree(g_target_report_data);
	g_target_report_data = NULL;

	kfree(fixed_point_label->fpt_cnt);
	fixed_point_label->fpt_cnt = NULL;
	kfree(fixed_point_label->finger_id);
	fixed_point_label->finger_id = NULL;
	kfree(fixed_point_label->y);
	fixed_point_label->y = NULL;
	kfree(fixed_point_label->x);
	fixed_point_label->x = NULL;
	kfree(fixed_point_label);
	fixed_point_label = NULL;

#if (HX_SMART_WAKEUP == 0x01)
	kfree(wake_event_buffer);
	wake_event_buffer = NULL;
	kfree(hx_touch_data->hx_event_buf);
	hx_touch_data->hx_event_buf = NULL;
#endif
	kfree(hx_touch_data->hx_rawdata_buf);
	hx_touch_data->hx_rawdata_buf = NULL;
	kfree(hx_touch_data->hx_coord_buf);
	hx_touch_data->hx_coord_buf = NULL;
}

static int himax_ts_work_status(struct himax_ts_data *ts)
{
	/* 1: normal */
	int result = HX_REPORT_COORD;

	hx_touch_data->diag_cmd = ts->diag_cmd;
	if (hx_touch_data->diag_cmd)
		result = HX_REPORT_COORD_RAWDATA;

#if (HX_SMART_WAKEUP == 0x01)
	if (atomic_read(&ts->suspend_mode) && (ts->SMWP_enable) &&
	    (!hx_touch_data->diag_cmd))
		result = HX_REPORT_SMWP_EVENT;
#endif
	/* I("Now Status is %d\n", result); */
	return result;
}

static int himax_touch_get(struct himax_ts_data *ts, uint8_t *buf, int ts_path,
			   int ts_status)
{
	if (g_ts_dbg != 0)
		I("%s: Entering, ts_status=%d!\n", __func__, ts_status);

	switch (ts_path) {
	/*normal*/
	case HX_REPORT_COORD:
#if (HX_EXCP_RECOVERY == 0x01)
		if (HX_EXCP_RESET_ACTIVATE) {
			if (!himax_mcu_read_event_stack(buf, 128)) {
				E("%s: can't read data from chip!\n", __func__);
				ts_status = HX_TS_GET_DATA_FAIL;
			}
		} else {
			if (!himax_mcu_read_event_stack(
				    buf, hx_touch_data->touch_info_size)) {
				E("%s: can't read data from chip!\n", __func__);
				ts_status = HX_TS_GET_DATA_FAIL;
			}
		}
		break;
#else
		if (!himax_mcu_read_event_stack(
			    buf, hx_touch_data->touch_info_size)) {
			E("%s: can't read data from chip!\n", __func__);
			ts_status = HX_TS_GET_DATA_FAIL;
		}
		break;
#endif

#if (HX_SMART_WAKEUP == 0x01)

	/*SMWP*/
	case HX_REPORT_SMWP_EVENT:
		__pm_wakeup_event(&ts->ts_SMWP_wake_lock, TS_WAKE_LOCK_TIMEOUT);
		msleep(20);
		himax_mcu_burst_enable(0);

		if (!himax_mcu_read_event_stack(buf,
						hx_touch_data->event_size)) {
			E("%s: can't read data from chip!\n", __func__);
			ts_status = HX_TS_GET_DATA_FAIL;
		}
		break;
#endif
	case HX_REPORT_COORD_RAWDATA:
		if (!himax_mcu_read_event_stack(buf, 128)) {
			E("%s: can't read data from chip!\n", __func__);
			ts_status = HX_TS_GET_DATA_FAIL;
		}
		break;
	default:
		break;
	}

	return ts_status;
}

/* start error_control*/
static int himax_checksum_cal(struct himax_ts_data *ts, uint8_t *buf,
			      int ts_path, int ts_status)
{
	uint16_t check_sum_cal = 0;
	int32_t i = 0;
	int length = 0;
	int zero_cnt = 0;
	int raw_data_sel = 0;
	int ret_val = ts_status;

	if (g_ts_dbg != 0)
		I("%s: Entering, ts_status=%d!\n", __func__, ts_status);

	/* Normal */
	switch (ts_path) {
	case HX_REPORT_COORD:
		length = hx_touch_data->touch_info_size;
		break;
#if (HX_SMART_WAKEUP == 0x01)
		/* SMWP */
	case HX_REPORT_SMWP_EVENT:
		length = (GEST_PTLG_ID_LEN + GEST_PTLG_HDR_LEN);
		break;
#endif
	case HX_REPORT_COORD_RAWDATA:
		length = hx_touch_data->touch_info_size;
		break;
	default:
		I("%s, Normal error!\n", __func__);
		ret_val = HX_PATH_FAIL;
		goto END_FUNCTION;
	}

	for (i = 0; i < length; i++) {
		check_sum_cal += buf[i];
		if (buf[i] == 0x00)
			zero_cnt++;
	}

	if (check_sum_cal % 0x100 != 0) {
		I("point data_checksum not match check_sum_cal: 0x%02X",
		  check_sum_cal);
		ret_val = HX_CHKSUM_FAIL;
	} else if (zero_cnt == length) {
		if (ts->use_irq)
			I("[HIMAX TP MSG] All Zero event\n");

		ret_val = HX_CHKSUM_FAIL;
	} else {
		raw_data_sel = buf[HX_TOUCH_INFO_POINT_CNT] >> 4 & 0x0F;
		/*I("%s:raw_out_sel=%x , hx_touch_data->diag_cmd=%x.\n",*/
		/*		__func__, raw_data_sel,*/
		/*		hx_touch_data->diag_cmd);*/
		/*raw data out not match skip it*/
		if ((raw_data_sel != 0x0F) &&
		    (raw_data_sel != hx_touch_data->diag_cmd)) {
			/*I("%s:raw data out not match.\n", __func__);*/
			if (!hx_touch_data->diag_cmd) {
				/*Need to clear event stack here*/
				himax_mcu_read_event_stack(
					buf,
					(128 - hx_touch_data->touch_info_size));
				/*I("%s: size =%d, buf[0]=%x ,buf[1]=%x,*/
				/*	buf[2]=%x, buf[3]=%x.\n",*/
				/*	__func__,*/
				/*	(128-hx_touch_data->touch_info_size),*/
				/*	buf[0], buf[1], buf[2], buf[3]);*/
				/*I("%s:also clear event stack.\n", __func__);*/
			}
			ret_val = HX_READY_SERVE;
		}
	}

END_FUNCTION:
	if (g_ts_dbg != 0)
		I("%s: END, ret_val=%d!\n", __func__, ret_val);
	return ret_val;
}

#if (HX_EXCP_RECOVERY == 0x01)
static int himax_ts_event_check(struct himax_ts_data *ts, uint8_t *buf,
				int ts_path, int ts_status)
{
	uint32_t hx_excp_event = 0;
	uint32_t hx_zero_event = 0;
	int shaking_ret = 0;

	uint32_t loop_i = 0;
	uint32_t length = 0;
	int ret_val = ts_status;

	if (g_ts_dbg != 0)
		I("%s: Entering, ts_status=%d!\n", __func__, ts_status);

	/* Normal */
	switch (ts_path) {
	case HX_REPORT_COORD:
		length = hx_touch_data->touch_info_size;
		break;
#if (HX_SMART_WAKEUP == 0x01)
		/* SMWP */
	case HX_REPORT_SMWP_EVENT:
		length = (GEST_PTLG_ID_LEN + GEST_PTLG_HDR_LEN);
		break;
#endif
	case HX_REPORT_COORD_RAWDATA:
		length = hx_touch_data->touch_info_size;
		break;
	default:
		I("%s, Neither Normal Nor SMWP error!\n", __func__);
		ret_val = HX_PATH_FAIL;
		goto END_FUNCTION;
	}

	if (g_ts_dbg != 0)
		I("Now Path=%d, Now status=%d, length=%d\n", ts_path, ts_status,
		  length);

	for (loop_i = 0; loop_i < length; loop_i++) {
		if (ts_path == HX_REPORT_COORD ||
		    ts_path == HX_REPORT_COORD_RAWDATA) {
			/* case 2 EXCEPTION recovery flow-Disable */
			if (buf[loop_i] == 0x00) {
				hx_zero_event++;
			} else {
				hx_zero_event = 0;
				g_zero_event_count = 0;
			}
		}
	}

	if ((hx_excp_event == length || hx_zero_event == length) &&
	    (HX_EXCP_RESET_ACTIVATE == 0) && (hx_touch_data->diag_cmd == 0) &&
	    (ts->in_self_test == 0)) {
		shaking_ret = himax_mcu_ic_excp_recovery(hx_excp_event,
							 hx_zero_event, length);

		if (shaking_ret == HX_EXCP_EVENT) {
			himax_excp_hw_reset();
			ret_val = HX_EXCP_EVENT;
		} else if (shaking_ret == HX_ZERO_EVENT_COUNT) {
			ret_val = HX_ZERO_EVENT_COUNT;
		} else {
			I("I2C running. Nothing to be done!\n");
			ret_val = HX_IC_RUNNING;
		}

		/* drop 1st interrupts after chip reset */
	} else if (HX_EXCP_RESET_ACTIVATE) {
		HX_EXCP_RESET_ACTIVATE = 0;
		I("%s: Skip by HX_EXCP_RESET_ACTIVATE.\n", __func__);
		ret_val = HX_EXCP_REC_OK;
	}

END_FUNCTION:
	if (g_ts_dbg != 0)
		I("%s: END, ret_val=%d!\n", __func__, ret_val);

	return ret_val;
}
#endif

static int himax_err_ctrl(struct himax_ts_data *ts, uint8_t *buf, int ts_path,
			  int ts_status)
{
	ts_status = himax_checksum_cal(ts, buf, ts_path, ts_status);
	if (ts_status == HX_CHKSUM_FAIL) {
		goto CHK_FAIL;
	} else {
#if (HX_EXCP_RECOVERY == 0x01)
		/* continuous N times record, not total N times. */
		g_zero_event_count = 0;
#endif
		goto END_FUNCTION;
	}

CHK_FAIL:
#if (HX_EXCP_RECOVERY == 0x01)
	ts_status = himax_ts_event_check(ts, buf, ts_path, ts_status);
#endif

END_FUNCTION:
	if (g_ts_dbg != 0)
		I("%s: END, ts_status=%d!\n", __func__, ts_status);
	return ts_status;
}
/* end error_control*/

/* start distribute_data*/
static int himax_distribute_touch_data(uint8_t *buf, int ts_path, int ts_status)
{
	uint8_t hx_state_info_pos = hx_touch_data->touch_info_size - 3;

	if (g_ts_dbg != 0)
		I("%s: Entering, ts_status=%d!\n", __func__, ts_status);

	if (ts_path == HX_REPORT_COORD) {
		memcpy(hx_touch_data->hx_coord_buf, &buf[0],
		       hx_touch_data->touch_info_size);

		if (buf[hx_state_info_pos] != 0xFF &&
		    buf[hx_state_info_pos + 1] != 0xFF)
			memcpy(hx_touch_data->hx_state_info,
			       &buf[hx_state_info_pos], 2);
		else
			memset(hx_touch_data->hx_state_info, 0x00,
			       sizeof(hx_touch_data->hx_state_info));

#if (HX_EXCP_RECOVERY == 0x01)
		if (HX_EXCP_RESET_ACTIVATE) {
			memcpy(hx_touch_data->hx_rawdata_buf,
			       &buf[hx_touch_data->touch_info_size],
			       hx_touch_data->touch_all_size -
				       hx_touch_data->touch_info_size);
		}
#endif

	} else if (ts_path == HX_REPORT_COORD_RAWDATA) {
		memcpy(hx_touch_data->hx_coord_buf, &buf[0],
		       hx_touch_data->touch_info_size);

		if (buf[hx_state_info_pos] != 0xFF &&
		    buf[hx_state_info_pos + 1] != 0xFF)
			memcpy(hx_touch_data->hx_state_info,
			       &buf[hx_state_info_pos], 2);
		else
			memset(hx_touch_data->hx_state_info, 0x00,
			       sizeof(hx_touch_data->hx_state_info));

		memcpy(hx_touch_data->hx_rawdata_buf,
		       &buf[hx_touch_data->touch_info_size],
		       hx_touch_data->touch_all_size -
			       hx_touch_data->touch_info_size);
#if (HX_SMART_WAKEUP == 0x01)
	} else if (ts_path == HX_REPORT_SMWP_EVENT) {
		memcpy(hx_touch_data->hx_event_buf, buf,
		       hx_touch_data->event_size);
#endif
	} else {
		E("%s, Fail Path!\n", __func__);
		ts_status = HX_PATH_FAIL;
	}

	if (g_ts_dbg != 0)
		I("%s: End, ts_status=%d!\n", __func__, ts_status);
	return ts_status;
}
/* end assign_data*/

/* start parse_report_data*/
int himax_parse_report_points(struct himax_ts_data *ts, int ts_path,
			      int ts_status)
{
	int x = 0, y = 0, w = 0;
	int base = 0;
	int event_id = 0, type_i = 0;
	int palm_id = 0;
	int32_t loop_i = 0;
	char *event_type[2] = { "[Finger]", "[Palm]" };

	if (g_ts_dbg != 0)
		I("%s: start!\n", __func__);

	ts->old_finger = ts->pre_finger_mask;
	if (ts->hx_point_num == 0) {
		if (g_ts_dbg != 0)
			I("%s: hx_point_num = 0!\n", __func__);
		return ts_status;
	}
	ts->pre_finger_mask = 0;
	hx_touch_data->finger_num =
		hx_touch_data->hx_coord_buf[ts->coordInfoSize - 4] & 0x0F;
	hx_touch_data->finger_on = 1;
	AA_press = 1;

	g_target_report_data->finger_num = hx_touch_data->finger_num;
	g_target_report_data->finger_on = hx_touch_data->finger_on;

	if (g_ts_dbg != 0)
		I("%s:finger_num = 0x%2X, finger_on = %d\n", __func__,
		  g_target_report_data->finger_num,
		  g_target_report_data->finger_on);

	for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) {
		base = loop_i * 4;
		x = hx_touch_data->hx_coord_buf[base] << 8 |
		    hx_touch_data->hx_coord_buf[base + 1];
		y = (hx_touch_data->hx_coord_buf[base + 2] << 8 |
		     hx_touch_data->hx_coord_buf[base + 3]);

		w = hx_touch_data
			    ->hx_coord_buf[(ts->nFinger_support * 4) + loop_i];

		if (g_ts_dbg != 0)
			D("%s: now parsing[%d]:x=%d, y=%d, w=%d\n", __func__,
			  loop_i, x, y, w);
/*
		if (ic_data->HX_IS_ID_EN) {
			x = (hx_touch_data->hx_coord_buf[base] & 0x3F) << 8 |
			    hx_touch_data->hx_coord_buf[base + 1];
			y = (hx_touch_data->hx_coord_buf[base + 2] & 0x3F)
				    << 8 |
			    hx_touch_data->hx_coord_buf[base + 3];
			if ((ic_data->HX_ID_PALM_EN) &&
			    (hx_touch_data->hx_coord_buf[base] >> 0x16)) {
				event_id = hx_touch_data->hx_coord_buf[base] >>
					   0x16;
				type_i = 1;
			} else
				event_id = hx_touch_data->hx_coord_buf[base] >>
					   0x06;
*/

		if (ic_data->HX_IS_ID_EN) {
			event_id = hx_touch_data->hx_coord_buf[base] >> 0x06;
			x = (hx_touch_data->hx_coord_buf[base] & 0x3f)  << 8 | hx_touch_data->hx_coord_buf[base + 1];
		}

		if (ic_data->HX_ID_PALM_EN) {
			palm_id = hx_touch_data->hx_coord_buf[base + 2] >> 0x06;
			y = (hx_touch_data->hx_coord_buf[base + 2] & 0x3f)  << 8 | hx_touch_data->hx_coord_buf[base + 3];
		}

		/*if ((event_id == 0) || (event_id == 3)) {*/ /*No touch event or Leave event*/
		if ((event_id == 0) || (event_id == 3)) { /*No touch event or Leave event*/
			x = 0xFFFF;
			y = 0xFFFF;
		}

		if (g_ts_dbg != 0) {
			if (ic_data->HX_IS_ID_EN) {
				switch (event_id) {
				case 1:
					I("Event Enter!\n");
					break;
				case 2:
					I("Event Moving!\n");
					break;
				case 3:
					I("Event Leave!\n");
					break;
				default:
					break;
				}
			}
			if (ic_data->HX_ID_PALM_EN) {
				if (palm_id == 1)
					I("Plam event\n");
			}
			I("Parsing[%d]:x=%d, y=%d, event_id=%d, palm_id=%d\n", loop_i, x, y, event_id, palm_id);
		}


		if (x >= 0 && x <= ts->pdata->abs_x_max && y >= 0 &&
		    y <= ts->pdata->abs_y_max) {
			hx_touch_data->finger_num--;

			g_target_report_data->x[loop_i] = x;
			g_target_report_data->y[loop_i] = y;
			g_target_report_data->w[loop_i] = w;
			g_target_report_data->finger_id[loop_i] = 1;

			if (!ts->first_pressed) {
				ts->first_pressed = 1;
				I("S1@%d, %d\n", x, y);
			}

			ts->pre_finger_data[loop_i][0] = x;
			ts->pre_finger_data[loop_i][1] = y;

			ts->pre_finger_mask =
				ts->pre_finger_mask + (1 << loop_i);
		} else { /* report coordinates */
			g_target_report_data->x[loop_i] = x;
			g_target_report_data->y[loop_i] = y;
			g_target_report_data->w[loop_i] = w;
			g_target_report_data->finger_id[loop_i] = 0;

			if (loop_i == 0 && ts->first_pressed == 1) {
				ts->first_pressed = 2;
				I("E1@%d, %d\n", ts->pre_finger_data[0][0],
				  ts->pre_finger_data[0][1]);
			}
		}
	}

	if (g_ts_dbg != 0) {
		for (loop_i = 0; loop_i < 10; loop_i++)
			D("DBG X=%d  Y=%d ID=%d\n",
			  g_target_report_data->x[loop_i],
			  g_target_report_data->y[loop_i],
			  g_target_report_data->finger_id[loop_i]);

		D("DBG finger number %d\n", g_target_report_data->finger_num);
	}

	if (g_ts_dbg != 0)
		I("%s: end!\n", __func__);
	return ts_status;
}

static int himax_parse_report_data(struct himax_ts_data *ts, int ts_path,
				   int ts_status)
{
	if (g_ts_dbg != 0)
		I("%s: start now_status=%d!\n", __func__, ts_status);

	EN_NoiseFilter =
		(hx_touch_data->hx_coord_buf[HX_TOUCH_INFO_POINT_CNT + 2] >> 3);
	/* I("EN_NoiseFilter=%d\n", EN_NoiseFilter); */
	EN_NoiseFilter = EN_NoiseFilter & 0x01;
	/* I("EN_NoiseFilter2=%d\n", EN_NoiseFilter); */
	p_point_num = ts->hx_point_num;

	if (hx_touch_data->hx_coord_buf[HX_TOUCH_INFO_POINT_CNT] == 0xff)
		ts->hx_point_num = 0;
	else
		ts->hx_point_num =
			hx_touch_data->hx_coord_buf[HX_TOUCH_INFO_POINT_CNT] &
			0x0f;

	switch (ts_path) {
	case HX_REPORT_COORD:
		ts_status = himax_parse_report_points(ts, ts_path, ts_status);
		break;
	case HX_REPORT_COORD_RAWDATA:
		/* touch monitor rawdata */
		if (debug_data != NULL) {
			if (debug_data->fp_set_diag_cmd(ic_data, hx_touch_data))
				I("%s:raw data_checksum not match\n", __func__);
		} else {
			E("%s,There is no init set_diag_cmd\n", __func__);
		}
		ts_status = himax_parse_report_points(ts, ts_path, ts_status);
		break;
#if (HX_SMART_WAKEUP == 0x01)
	case HX_REPORT_SMWP_EVENT:
		himax_wake_event_parse(ts, ts_status);
		break;
#endif
	default:
		E("%s:Fail Path!\n", __func__);
		ts_status = HX_PATH_FAIL;
		break;
	}
	if (g_ts_dbg != 0)
		I("%s: end now_status=%d!\n", __func__, ts_status);
	return ts_status;
}

/* end parse_report_data*/

void himax_report_all_leave_event(struct himax_ts_data *ts)
{
	int loop_i = 0;

	for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) {
#if (HX_PROTOCOL_A == 0x00)
		input_mt_slot(ts->input_dev, loop_i);
		input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
		input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0);
		input_report_abs(ts->input_dev, ABS_MT_PRESSURE, 0);
		input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0);
#endif
	}
	input_report_key(ts->input_dev, BTN_TOUCH, 0);
	input_sync(ts->input_dev);
}

void himax_mcu_clear_event_stack(void)
{
	uint32_t addr_clear_event_stack = 0x80060014;
	uint8_t data[DATA_LEN_4] = {0};

	I("%s: enter\n", __func__);
	himax_mcu_register_read(addr_clear_event_stack, DATA_LEN_4, data);
	data[0] |= 0x02;
	himax_mcu_register_write(addr_clear_event_stack, DATA_LEN_4, data);

}

/* start report_point*/
static void himax_finger_report(struct himax_ts_data *ts)
{
	int i = 0;
	bool valid = false;
	int debounce_cnt = 3620; /* 3620 * 8.3ms = 30 sec. */

	if (g_ts_dbg != 0) {
		I("%s:start hx_touch_data->finger_num=%d\n", __func__,
		  hx_touch_data->finger_num);
	}

	for (i = 0; i < ts->nFinger_support; i++) {
		if (ts->GTS_range > 0) {
			if ((g_target_report_data->x[i] != 0xFFFF) ||
			    (g_target_report_data->y[i] != 0xFFFF)) {
				/*
				 *I("report_data->x[i]=%d,y[i]=%d",
					g_target_report_data->x[i],
					g_target_report_data->y[i]);
				I("pre_report_data->pre_x[i]=%d,pre_y[i]=%d",
					fixed_point_label->x[i],
					fixed_point_label->y[i]);
				*/
				if ((fixed_point_label->x[i] == 0xFFFF) &&
				    (fixed_point_label->y[i] == 0xFFFF)) {
					/*I("fixed point appears\n");*/
					fixed_point_label->fpt_cnt[i] = 0;
					fixed_point_label->x[i] =
						g_target_report_data->x[i];
					fixed_point_label->y[i] =
						g_target_report_data->y[i];
				}
				if ((g_target_report_data->x[i] -
					     fixed_point_label->x[i] <
				     ts->GTS_range) &&
				    (fixed_point_label->x[i] -
					     g_target_report_data->x[i] <
				     ts->GTS_range) &&
				    (fixed_point_label->y[i] -
					     g_target_report_data->y[i] <
				     ts->GTS_range) &&
				    (g_target_report_data->y[i] -
					     fixed_point_label->y[i] <
				     ts->GTS_range)) { /* in range */
					fixed_point_label->fpt_cnt[i]++;
					/*I("fpt_cnt[%d] = %d\n", i, fixed_point_label->fpt_cnt[i]);*/
				} else { /* out of range */
					fixed_point_label->fpt_cnt[i] = 0;
					fixed_point_label->x[i] = 0xFFFF;
					fixed_point_label->y[i] = 0xFFFF;
				}
			} else { /* finger leave */
				fixed_point_label->fpt_cnt[i] = 0;
				fixed_point_label->x[i] = 0xFFFF;
				fixed_point_label->y[i] = 0xFFFF;
			}
			if (fixed_point_label->fpt_cnt[i] >
			    debounce_cnt) { /* 3620 * 8.3ms = 30 sec. */
				I("[Ghost] point happens !!!");
				fixed_point_label->fpt_cnt[i] = 0;
				himax_report_all_leave_event(ts);
				himax_mcu_system_reset();
				return;
			}
		}
		if (g_target_report_data->x[i] >= 0 &&
		    g_target_report_data->x[i] <= ts->pdata->abs_x_max &&
		    g_target_report_data->y[i] >= 0 &&
		    g_target_report_data->y[i] <= ts->pdata->abs_y_max)
			valid = true;
		else
			valid = false;
		if (g_ts_dbg != 0)
			I("valid=%d\n", valid);
		if (valid) {
			if (g_ts_dbg != 0) {
				I("report_data->x[%d]=%d,y[%d]=%d,w[%d]=%d",
				  i, g_target_report_data->x[i],
				  i, g_target_report_data->y[i],
				  i, g_target_report_data->w[i]);
			}
#if (HX_PROTOCOL_A == 0x00)
			input_mt_slot(ts->input_dev, i);
#else
			input_report_key(ts->input_dev, BTN_TOUCH, 1);
#endif
			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR,
					 g_target_report_data->w[i]);
#if (HX_PROTOCOL_A == 0x00)
			input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR,
					 g_target_report_data->w[i]);
			input_report_abs(ts->input_dev, ABS_MT_PRESSURE,
					 g_target_report_data->w[i]);
#else
			input_report_abs(ts->input_dev, ABS_MT_TRACKING_ID, i);
#endif
			input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
					 g_target_report_data->x[i]);
			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
					 g_target_report_data->y[i]);
#if (HX_PROTOCOL_A == 0x00)
			ts->last_slot = i;
			input_mt_report_slot_state(ts->input_dev,
						   MT_TOOL_FINGER, 1);
#else
			input_mt_sync(ts->input_dev);
#endif
		} else {
#if (HX_PROTOCOL_A == 0x00)
			input_mt_slot(ts->input_dev, i);
			input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
			input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0);
			input_report_abs(ts->input_dev, ABS_MT_PRESSURE, 0);
			input_mt_report_slot_state(ts->input_dev,
						   MT_TOOL_FINGER, 0);
#endif
		}
	}
#if (HX_PROTOCOL_A == 0x00)
	input_report_key(ts->input_dev, BTN_TOUCH, 1);
#endif
	input_sync(ts->input_dev);

	if (g_ts_dbg != 0)
		I("%s:end\n", __func__);
}

static void himax_finger_leave(struct himax_ts_data *ts)
{
#if (HX_PROTOCOL_A == 0x00)
	int32_t loop_i = 0;
#endif

	if (g_ts_dbg != 0)
		I("%s: start!\n", __func__);

	hx_touch_data->finger_on = 0;
	g_target_report_data->finger_on = 0;
	g_target_report_data->finger_num = 0;
	AA_press = 0;

#if (HX_PROTOCOL_A == 0x01)
	input_mt_sync(ts->input_dev);
#endif
#if (HX_PROTOCOL_A == 0x00)
	for (loop_i = 0; loop_i < ts->nFinger_support; loop_i++) {
		input_mt_slot(ts->input_dev, loop_i);
		input_report_abs(ts->input_dev, ABS_MT_TOUCH_MAJOR, 0);
		input_report_abs(ts->input_dev, ABS_MT_WIDTH_MAJOR, 0);
		input_report_abs(ts->input_dev, ABS_MT_PRESSURE, 0);
		input_mt_report_slot_state(ts->input_dev, MT_TOOL_FINGER, 0);
	}
#endif
	if (ts->pre_finger_mask > 0)
		ts->pre_finger_mask = 0;

	if (ts->first_pressed == 1) {
		ts->first_pressed = 2;
		I("E1@%d, %d\n", ts->pre_finger_data[0][0],
		  ts->pre_finger_data[0][1]);
	}

	/*if (ts->debug_log_level & BIT(1))*/
	/*	himax_log_touch_event(x, y, w, loop_i, EN_NoiseFilter,*/
	/*			HX_FINGER_LEAVE); */

	input_report_key(ts->input_dev, BTN_TOUCH, 0);
	input_sync(ts->input_dev);

	if (g_ts_dbg != 0)
		I("%s: end!\n", __func__);
}

static void himax_report_points(struct himax_ts_data *ts)
{
	if (g_ts_dbg != 0)
		I("%s: start!\n", __func__);

	if (ts->hx_point_num != 0)
		himax_finger_report(ts);
	else
		himax_finger_leave(ts);

	Last_EN_NoiseFilter = EN_NoiseFilter;

	if (g_ts_dbg != 0)
		I("%s: end!\n", __func__);
}
/* end report_points*/

int himax_report_data(struct himax_ts_data *ts, int ts_path, int ts_status)
{
	if (g_ts_dbg != 0)
		I("%s: Entering, ts_status=%d!\n", __func__, ts_status);

	if (ts_path == HX_REPORT_COORD || ts_path == HX_REPORT_COORD_RAWDATA) {
		/* Touch Point information */
		himax_report_points(ts);

#if (HX_SMART_WAKEUP == 0x01)
	} else if (ts_path == HX_REPORT_SMWP_EVENT) {
		himax_wake_event_report();
#endif
	} else {
		E("%s:Fail Path!\n", __func__);
		ts_status = HX_PATH_FAIL;
	}

	if (g_ts_dbg != 0)
		I("%s: END, ts_status=%d!\n", __func__, ts_status);
	return ts_status;
}
/* end report_data */

static int himax_ts_operation(struct himax_ts_data *ts, int ts_path,
			      int ts_status)
{
	uint8_t hw_reset_check[2];
#if (FCA_PROTOCOL_EN == 0x01)
	uint8_t loop_i;
	uint8_t Finger_i = 0;
	uint16_t x_coord[5];
	uint16_t y_coord[5];

	memset(x_coord, 0xFFFF, 5 * sizeof(uint16_t));
	memset(y_coord, 0xFFFF, 5 * sizeof(uint16_t));
#endif
	memset(ts->xfer_buff, 0x00, 128 * sizeof(uint8_t));
	memset(hw_reset_check, 0x00, sizeof(hw_reset_check));

	ts_status = himax_touch_get(ts, ts->xfer_buff, ts_path, ts_status);
	if (ts_status == HX_TS_GET_DATA_FAIL)
		goto END_FUNCTION;
#if (FCA_PROTOCOL_EN == 0x00)
	ts_status =
		himax_distribute_touch_data(ts->xfer_buff, ts_path, ts_status);
	ts_status = himax_err_ctrl(ts, ts->xfer_buff, ts_path, ts_status);

	if (ts_status == HX_REPORT_DATA || ts_status == HX_TS_NORMAL_END ||
	    ts_status == HX_READY_SERVE)
		ts_status = himax_parse_report_data(ts, ts_path, ts_status);
	else
		goto END_FUNCTION;

	ts_status = himax_report_data(ts, ts_path, ts_status);

#else
	for (loop_i = 0; loop_i < 25; loop_i++) {
		if (loop_i == 0)
			I("%s: Msg_cnt = 0x%2X\n", __func__, ts->xfer_buff[0]);
		else if ((loop_i % 4) == 0 && loop_i < 24) {
			if (ts->xfer_buff[loop_i] >> 7) {
				x_coord[Finger_i] =
					(((ts->xfer_buff[loop_i] & 0x07) << 8) |
					 ts->xfer_buff[loop_i -
						       1]); /* (HI & 0x07) >> 0x08 | LO*/
				y_coord[Finger_i++] =
					(((ts->xfer_buff[loop_i + 2] & 0x07)
					  << 8) |
					 ts->xfer_buff[loop_i + 1]);
			}
		}
	}
	if (!Finger_i) {
		himax_finger_leave(ts);
	} else {
		for (loop_i = 0; loop_i < Finger_i; loop_i++) {
			if (x_coord[loop_i] != 0xFFFF) {
				I("x_coord[%d] = %2d\n", loop_i,
				  x_coord[loop_i]);
				I("y_coord[%d] = %2d\n", loop_i,
				  y_coord[loop_i]);
			}
			input_mt_slot(ts->input_dev,
				      loop_i); //input_mt_slot(input, 0);
			input_report_abs(ts->input_dev, ABS_MT_PRESSURE, 1);
			input_report_abs(ts->input_dev, ABS_MT_POSITION_X,
					 x_coord[loop_i]);
			input_report_abs(ts->input_dev, ABS_MT_POSITION_Y,
					 y_coord[loop_i]);
			input_mt_report_slot_state(ts->input_dev,
						   MT_TOOL_FINGER, 1);
			input_report_key(ts->input_dev, BTN_TOUCH, 1);
			input_sync(ts->input_dev);
		}
	}

	goto END_FUNCTION;
#endif

END_FUNCTION:
	return ts_status;
}

void himax_fail_det_work(void)
{
	uint8_t data[8] = { 0 };
	uint8_t tmp_data[DATA_LEN_4] = { 0 };
	/*
	 *	uint8_t addr[4] = {0xD4, 0x74, 0x00, 0x10};
	 *	unit32_t tmp_addr_32 = 0x100074D4;
	 *	Clear Simulation Register
	 *	himax_mcu_register_write(tmp_addr_32, DATA_LEN_4, data);
	 */
	g_core_fp.fp_dd_clk_set(true);
	g_core_fp.fp_dd_reg_en(true);

	himax_mcu_dd_reg_read(0xE5, 0, 8, data, 0);
	I("%s E5_Bank0: para[1]=0x%2.2X,para[2]=0x%2.2X, para[3]=0x%2.2X\n",
	  __func__, data[1], data[2], data[3]);
	I("%s E5_Bank0: para[4]=0x%2.2X,para[5]=0x%2.2X,para[6]=0x%2.2X, para[7]=0x%2.2X\n",
	  __func__, data[4], data[5], data[6], data[7]);

	himax_mcu_dd_reg_read(0xE5, 0, 8, data, 1);
	I("%s E5_Bank1: para[1]=0x%2.2X,para[2]=0x%2.2X, para[3]=0x%2.2X\n",
	  __func__, data[1], data[2], data[3]);
	I("%s E5_Bank1: para[4]=0x%2.2X,para[5]=0x%2.2X,para[6]=0x%2.2X, para[7]=0x%2.2X\n",
	  __func__, data[4], data[5], data[6], data[7]);

	himax_mcu_dd_reg_read(0xE5, 0, 8, data, 3);
	I("%s E5_Bank3: para[1]=0x%2.2X,para[2]=0x%2.2X, para[3]=0x%2.2X, para[4]=0x%2.2X\n",
	  __func__, data[1], data[2], data[3], data[4]);
	I("%s E5_Bank3: para[5]=0x%2.2X,para[6]=0x%2.2X, para[7]=0x%2.2X\n",
	  __func__, data[5], data[6], data[7]);

	g_core_fp.fp_dd_clk_set(false);

	I("%s: now read GPIO[1] Fail information.\n", __func__);

	himax_mcu_register_read(addr_fail_det_GPIO1_msg, DATA_LEN_4, tmp_data);
	I("%s: 100074C0 value is: tmp_data[1] = 0x%2.2x, tmp_data[1] = 0x%2.2x\n",
	  __func__, tmp_data[0], tmp_data[1]);
	I("%s: 100074C0 value is: tmp_data[2] = 0x%2.2x, tmp_data[3] = 0x%2.2x\n",
	  __func__, tmp_data[2], tmp_data[3]);

	/*	It depends on customer: */
	goto AP_recovery;

AP_recovery:

	I("%s: Now FAIL_DET pulls high means IC need external recovery\n",
	  __func__);
#if (HX_RST_PIN_FUNC == 0x01)
	himax_mcu_tp_lcm_pin_reset();
#elif (HX_RST_PIN_FUNC == 0x02)
	/* Need Customer do AP recovery */
#endif
}

void himax_ts_work(struct himax_ts_data *ts)
{
	int ts_status = HX_TS_NORMAL_END;
	int ts_path = 0;

	if (debug_data != NULL)
		debug_data->fp_ts_dbg_func(ts, HX_FINGER_ON);

	ts_path = himax_ts_work_status(ts);


	switch (ts_path) {
	case HX_REPORT_COORD:
		ts_status = himax_ts_operation(ts, ts_path, ts_status);
		break;
	case HX_REPORT_COORD_RAWDATA:
		ts_status = himax_ts_operation(ts, ts_path, ts_status);
		break;
#if (HX_SMART_WAKEUP == 0x01)
	case HX_REPORT_SMWP_EVENT:
		ts_status = himax_ts_operation(ts, ts_path, ts_status);
		break;
#endif
	default:
		E("%s:Path Fault! value=%d\n", __func__, ts_path);
		goto END_FUNCTION;
	}

	if (ts_status == HX_TS_GET_DATA_FAIL)
		goto GET_TOUCH_FAIL;
	else
		goto END_FUNCTION;

GET_TOUCH_FAIL:
	I("%s: Now reset the Touch chip.\n", __func__);
#if (HX_RST_PIN_FUNC == 0x01)
	himax_mcu_ic_reset(false, true);
#elif (HX_RST_PIN_FUNC == 0x02)
	/* Need Customer do TP reset pin */
#else
	himax_mcu_system_reset();
#endif
END_FUNCTION:
	if (debug_data != NULL)
		debug_data->fp_ts_dbg_func(ts, HX_FINGER_LEAVE);
}
/*end ts_work*/
enum hrtimer_restart himax_ts_timer_func(struct hrtimer *timer)
{
	struct himax_ts_data *ts;

	ts = container_of(timer, struct himax_ts_data, timer);
	queue_work(ts->himax_wq, &ts->work);
	hrtimer_start(&ts->timer, ktime_set(0, 12500000), HRTIMER_MODE_REL);
	return HRTIMER_NORESTART;
}

#if (HX_BOOT_UPGRADE == 0x01)
static void himax_boot_upgrade(struct work_struct *work)
{
	if (i_get_FW() != 0)
		return;

	hx_mcu_bin_desc_get((unsigned char *)hxfw->data, HX1K);

	if (g_boot_upgrade_flag == true) {
		I("%s: Forced upgrade\n", __func__);
		goto UPDATE_FW;
	}

	if (himax_auto_update_check() != 0)
		goto SKIP_UPDATE_FW;

UPDATE_FW:
	if (i_update_FW() <= 0)
		E("%s: Update FW fail\n", __func__);
	else {
		g_boot_upgrade_flag = false;
		I("%s: Update FW success\n", __func__);
	}
SKIP_UPDATE_FW:
	release_firmware(hxfw);
	hxfw = NULL;
}
#endif

#if defined(HX_CONFIG_FB) || defined(HX_CONFIG_DRM)
static void himax_fb_register(struct work_struct *work)
{
	int ret = 0;

	struct himax_ts_data *ts =
		container_of(work, struct himax_ts_data, work_att.work);

	I("%s in\n", __func__);
#if defined(HX_CONFIG_FB)
	ts->fb_notif.notifier_call = fb_notifier_callback;
	ret = fb_register_client(&ts->fb_notif);
#elif defined(HX_CONFIG_DRM)
#if defined(__HIMAX_MOD__)
	hx_msm_drm_register_client =
		(void *)kallsyms_lookup_name("msm_drm_register_client");
	if (hx_msm_drm_register_client != NULL) {
		ts->fb_notif.notifier_call = drm_notifier_callback;
		ret = hx_msm_drm_register_client(&ts->fb_notif);
	} else
		E("hx_msm_drm_register_client is NULL\n");
#else
	ts->fb_notif.notifier_call = drm_notifier_callback;
	ret = msm_drm_register_client(&ts->fb_notif);
#endif
#endif
	if (ret)
		E("Unable to register fb_notifier: %d\n", ret);
}
#endif

#if defined(HX_CONTAINER_SPEED_UP)
static void himax_resume_work_func(struct work_struct *work)
{
	himax_chip_common_resume(private_ts);
}

#endif
int hx_ic_register(void)
{
	int ret = !NO_ERR;

#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83193)
	if (_hx83193_init()) {
		ret = NO_ERR;
		goto END;
	}
#endif
#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83191)
	if (_hx83191_init()) {
		ret = NO_ERR;
		goto END;
	}
#endif
#if defined(CONFIG_TOUCHSCREEN_HIMAX_IC_HX83192)
	if (_hx83192_init()) {
		ret = NO_ERR;
		goto END;
	}
#endif
END:
	if (ret != NO_ERR)
		E("%s: There is no IC!\n", __func__);

	return ret;
}

int himax_chip_common_init(void)
{
	int i = 0, ret = 0, idx = 0;
	int err = PROBE_FAIL;
	struct himax_ts_data *ts = private_ts;
	struct himax_i2c_platform_data *pdata;

	ts->GTS_range = 4;
	himax_print_define_function();

#if defined(__EMBEDDED_FW__)
	g_embedded_fw.size = (size_t)_binary___Himax_firmware_bin_end -
			     (size_t)_binary___Himax_firmware_bin_start;
#endif
	ts->xfer_buff =devm_kzalloc(ts->dev, 128 * sizeof(uint8_t), GFP_KERNEL);
	if (ts->xfer_buff == NULL) {
		err = -ENOMEM;
		goto err_xfer_buff_fail;
	}

	pdata = kzalloc(sizeof(struct himax_i2c_platform_data), GFP_KERNEL);
	if (pdata == NULL) { /*Allocate Platform data space*/
		err = -ENOMEM;
		goto err_dt_platform_data_fail;
	}

	ic_data = kzalloc(sizeof(struct himax_ic_data), GFP_KERNEL);
	if (ic_data == NULL) { /*Allocate IC data space*/
		err = -ENOMEM;
		goto err_dt_ic_data_fail;
	}

	/* allocate report data */
	hx_touch_data = kzalloc(sizeof(struct himax_report_data), GFP_KERNEL);
	if (hx_touch_data == NULL) {
		err = -ENOMEM;
		goto err_alloc_touch_data_failed;
	}

	ts->pdata = pdata;
	//设备树解析
	if (himax_parse_dt(ts, pdata) < 0) {
		I(" pdata is NULL for DT\n");
		goto err_alloc_dt_pdata_failed;
	}

	ts->lcm_gpio = pdata->RESX;

#if (HX_RST_PIN_FUNC == 0x01) 
	ts->rst_gpio = pdata->tp_ext_rstn;
#endif
	//gpio 配置
	himax_gpio_power_config(pdata);

	g_hx_chip_inited = 0;

	if (hx_ic_register() != NO_ERR) {
		E("%s: can't detect IC!\n", __func__);
		goto error_ic_detect_failed;
	}

	if (!himax_mcu_calculateChecksum(FW_SIZE_128k)) {
		E("%s: check flash fail, please upgrade FW\n", __func__);
#if (HX_BOOT_UPGRADE == 0x01)
		g_boot_upgrade_flag = true;
#endif
	} else {
		himax_mcu_reload_disable(0);
		himax_mcu_power_on_init();
		himax_mcu_read_FW_ver();

		himax_mcu_touch_information();
	}

#if (HX_BOOT_UPGRADE == 0x01)
	ts->himax_boot_upgrade_wq =
		create_singlethread_workqueue("HX_boot_upgrade");
	if (!ts->himax_boot_upgrade_wq) {
		E("allocate himax_boot_upgrade_wq failed\n");
		err = -ENOMEM;
		goto err_boot_upgrade_wq_failed;
	}
	INIT_DELAYED_WORK(&ts->work_boot_upgrade, himax_boot_upgrade);
	queue_delayed_work(ts->himax_boot_upgrade_wq, &ts->work_boot_upgrade,
			   msecs_to_jiffies(2000));
#endif

#if defined(HX_CONTAINER_SPEED_UP)
	ts->ts_int_workqueue =
		create_singlethread_workqueue("himax_ts_resume_wq");
	if (!ts->ts_int_workqueue) {
		E("%s: create ts_resume workqueue failed\n", __func__);
		goto err_create_ts_resume_wq_failed;
	}
	INIT_DELAYED_WORK(&ts->ts_int_work, himax_resume_work_func);
#endif
	calculate_point_number();

#if defined(CONFIG_OF)
	ts->power = pdata->power;
#endif
	/*calculate the i2c data size*/
	himax_calcDataSize();

#if defined(CONFIG_OF)
	ts->pdata->abs_pressure_min = 0;
	ts->pdata->abs_pressure_max = 200;
	ts->pdata->abs_width_min = 0;
	ts->pdata->abs_width_max = 200;
#endif
	ts->suspended = false;

#if (HX_PROTOCOL_A == 0x01)
	ts->protocol_type = PROTOCOL_TYPE_A;
#else
	ts->protocol_type = PROTOCOL_TYPE_B;
#endif
	I("%s: Use Protocol Type %c\n", __func__,
	  ts->protocol_type == PROTOCOL_TYPE_A ? 'A' : 'B');

	ret = himax_input_register(ts);
	if (ret) {
		E("%s: Unable to register %s input device\n", __func__,
		  ts->input_dev->name);
		goto err_input_register_device_failed;
	}

	spin_lock_init(&ts->irq_lock);
	ts->initialized = true;

#if defined(HX_CONFIG_FB) || defined(HX_CONFIG_DRM)
	ts->himax_att_wq = create_singlethread_workqueue("HMX_ATT_request");

	if (!ts->himax_att_wq) {
		E(" allocate himax_att_wq failed\n");
		err = -ENOMEM;
		goto err_get_intr_bit_failed;
	}

	INIT_DELAYED_WORK(&ts->work_att, himax_fb_register);
	queue_delayed_work(ts->himax_att_wq, &ts->work_att,
			   msecs_to_jiffies(15000));
#endif

#if (HX_SMART_WAKEUP == 0x01)
	ts->SMWP_enable = 0;
	wakeup_source_init(&ts->ts_SMWP_wake_lock, HIMAX_common_NAME);
#endif

	/*touch data init*/
	err = himax_report_data_init();

	if (err)
		goto err_report_data_init_failed;

	if (himax_common_proc_init()) {
		E(" %s: himax_common proc_init failed!\n", __func__);
		goto err_creat_proc_file_failed;
	}

	himax_ts_register_interrupt();
#if (HX_BOOT_UPGRADE == 0x01)
	if (g_boot_upgrade_flag)
		himax_int_enable(0);
#endif

	himax_fail_det_register_interrupt();

#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG)
	if (himax_debug_init())
		E(" %s: debug initial failed!\n", __func__);
#endif

	g_hx_chip_inited = true;
	return 0;

err_creat_proc_file_failed:
	himax_report_data_deinit();
err_report_data_init_failed:
#if (HX_SMART_WAKEUP == 0x01)
	wakeup_source_trash(&ts->ts_SMWP_wake_lock);
#endif
#if defined(HX_CONFIG_FB) || defined(HX_CONFIG_DRM)
	cancel_delayed_work_sync(&ts->work_att);
	destroy_workqueue(ts->himax_att_wq);
err_get_intr_bit_failed:
#endif
	input_unregister_device(ts->input_dev);
err_input_register_device_failed:
	input_free_device(ts->input_dev);
	/*err_detect_failed:*/

#if defined(HX_CONTAINER_SPEED_UP)
	cancel_delayed_work_sync(&ts->ts_int_work);
	destroy_workqueue(ts->ts_int_workqueue);
err_create_ts_resume_wq_failed:
#endif

#if (HX_BOOT_UPGRADE == 0x01)
	cancel_delayed_work_sync(&ts->work_boot_upgrade);
	destroy_workqueue(ts->himax_boot_upgrade_wq);
err_boot_upgrade_wq_failed:
#endif

error_ic_detect_failed:
	himax_gpio_power_deconfig(pdata);
#if !defined(CONFIG_OF)
err_power_failed:
#endif
err_alloc_dt_pdata_failed:
	kfree(hx_touch_data);
	hx_touch_data = NULL;
err_alloc_touch_data_failed:
	kfree(ic_data);
	ic_data = NULL;
err_dt_ic_data_fail:
	kfree(pdata);
	pdata = NULL;
err_dt_platform_data_fail:
	devm_kfree(ts->dev, ts->xfer_buff);
	ts->xfer_buff = NULL;
err_xfer_buff_fail:
	probe_fail_flag = 1;
	return err;
}

void himax_chip_common_deinit(void)
{
	struct himax_ts_data *ts = private_ts;

	himax_ts_unregister_interrupt();

#if defined(CONFIG_TOUCHSCREEN_HIMAX_SELF_TEST)
	himax_self_test_data_clear();
#endif

#if defined(CONFIG_TOUCHSCREEN_HIMAX_DEBUG)
	himax_debug_remove();
#endif

	himax_common_proc_deinit();
	himax_report_data_deinit();

#if (HX_SMART_WAKEUP == 0x01)
	wakeup_source_trash(&ts->ts_SMWP_wake_lock);
#endif
#if defined(HX_CONFIG_FB)
	if (fb_unregister_client(&ts->fb_notif))
		E("Error occurred while unregistering fb_notifier.\n");
	cancel_delayed_work_sync(&ts->work_att);
	destroy_workqueue(ts->himax_att_wq);
#elif defined(HX_CONFIG_DRM)
#if defined(__HIMAX_MOD__)
	hx_msm_drm_unregister_client =
		(void *)kallsyms_lookup_name("msm_drm_unregister_client");
	if (hx_msm_drm_unregister_client != NULL) {
		if (hx_msm_drm_unregister_client(&ts->fb_notif))
			E("Error occurred while unregistering drm_notifier.\n");
	} else
		E("hx_msm_drm_unregister_client is NULL\n");
#else
	if (msm_drm_unregister_client(&ts->fb_notif))
		E("Error occurred while unregistering drm_notifier.\n");
#endif
	cancel_delayed_work_sync(&ts->work_att);
	destroy_workqueue(ts->himax_att_wq);
#endif
	input_unregister_device(ts->input_dev);
	input_free_device(ts->input_dev);
#if defined(HX_CONTAINER_SPEED_UP)
	cancel_delayed_work_sync(&ts->ts_int_work);
	destroy_workqueue(ts->ts_int_workqueue);
#endif

#if (HX_BOOT_UPGRADE == 0x01)
	cancel_delayed_work_sync(&ts->work_boot_upgrade);
	destroy_workqueue(ts->himax_boot_upgrade_wq);
#endif
	himax_gpio_power_deconfig(ts->pdata);
	himax_mcu_in_cmd_struct_free();

	kfree(hx_touch_data);
	hx_touch_data = NULL;
	kfree(ic_data);
	ic_data = NULL;
	devm_kfree(ts->dev, ts->xfer_buff);
	ts->xfer_buff = NULL;
	kfree(ts->pdata);
	ts->pdata = NULL;
	kfree(ts);
	ts = NULL;
	probe_fail_flag = 0;

	I("%s: Common section deinited!\n", __func__);
}

int himax_chip_common_suspend(struct himax_ts_data *ts)
{
	if (ts->suspended) {
		I("%s: Already suspended. Skipped.\n", __func__);
		goto END;
	} else {
		ts->suspended = true;
		I("%s: enter\n", __func__);
	}

	if (debug_data != NULL && g_flash_progress == 1) {
		I("[himax] %s: Flash dump is going, reject suspend\n",
		  __func__);
		goto END;
	}

#if (HX_SMART_WAKEUP == 0x01)
	if (gpio_is_valid(ts->pdata->PON)) {
		if (gpio_direction_output(ts->pdata->PON, 0))
			E("unable to set PON direction\n");
	}

	if (ts->SMWP_enable) {
		atomic_set(&ts->suspend_mode, 1);
		ts->pre_finger_mask = 0;
		I("[himax] %s: SMART_WAKEUP enable, reject suspend\n",
		  __func__);
		goto END;
	}

#endif
	himax_int_enable(0);

	if (!ts->use_irq) {
		int32_t cancel_state;

		cancel_state = cancel_work_sync(&ts->work);
		if (cancel_state)
			himax_int_enable(1);
	}

	/*ts->first_pressed = 0;*/
	atomic_set(&ts->suspend_mode, 1);
	ts->pre_finger_mask = 0;

END:
	if (ts->in_self_test == 1)
		ts->suspend_resume_done = 1;

	I("%s: END\n", __func__);

	return 0;
}

int himax_chip_common_resume(struct himax_ts_data *ts)
{
	I("%s: enter\n", __func__);

	if (ts->suspended == false) {
		I("%s: It had entered resume, skip this step\n", __func__);
		goto END;
	} else {
		ts->suspended = false;
	}

#if (HX_EXCP_RECOVERY == 0x01)
	/* continuous N times record, not total N times. */
	g_zero_event_count = 0;
#endif

	atomic_set(&ts->suspend_mode, 0);
	ts->diag_cmd = 0;

#if (HX_RST_PIN_FUNC == 0x01)
	himax_mcu_ic_reset(false, false);
#elif (HX_RST_PIN_FUNC == 0x02)
	/* Need Customer do TP reset pin */
#endif

#if (HX_SMART_WAKEUP == 0x01)
	if (gpio_is_valid(ts->pdata->PON)) {
		if (gpio_direction_output(ts->pdata->PON, 1))
			E("unable to set PON direction\n");
	}
#endif
	himax_report_all_leave_event(ts);

	himax_int_enable(1);

END:
	if (ts->in_self_test == 1)
		ts->suspend_resume_done = 1;

	I("%s: END\n", __func__);
	return 0;
}
